From bcff545dd7f926165585e1c63e8c7777090f5a0f Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 3 Nov 2025 09:25:16 +0200 Subject: [PATCH 01/19] BUG: Menue showing in claims in personal mode --- .../pat_profile/package_tools/patient_claim_or_statement.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3932042b..8477da3d 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 @@ -55,7 +55,7 @@ class _PatientClaimOrStatementState extends State { ], ), Visibility( - visible: patientManagerProvider.personalMode, + visible: !patientManagerProvider.personalMode, child: Positioned( right: 10, bottom: 10, From 52f9eb7ba619c61c121401da8d9975008407af98 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 3 Nov 2025 10:18:29 +0200 Subject: [PATCH 02/19] BUG: Add card refresh list --- .DS_Store | Bin 10244 -> 10244 bytes .../mih_providers/mzansi_wallet_provider.dart | 5 - .../builder/build_loyalty_card_list.dart | 35 +++- .../components/mih_add_card_window.dart | 19 +- .../mzansi_wallet/mih_wallet.dart | 21 ++- .../package_tools/mih_cards.dart | 175 ++++++++++-------- .../mih_mzansi_wallet_services.dart | 42 +++-- 7 files changed, 166 insertions(+), 131 deletions(-) diff --git a/.DS_Store b/.DS_Store index b2d3ca66295693fed4507dd7c2f61764b586e290..d4d2f162e22f008e4dae8f6d4e92bb2db320b967 100644 GIT binary patch delta 62 zcmZn(XbISGP>ivB^C2-4MyBk9%|FC%Ffo=-z9=OEeBS^C2-4My3RX%|FC%FfnFKz9=OE card.idloyalty_cards == cardId); notifyListeners(); 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 f44e7afb..11cdb53c 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 @@ -58,8 +58,12 @@ class _BuildLoyaltyCardListState extends State { ); } - void editCardWindow(MzansiProfileProvider mzansiProfileProvider, - BuildContext ctxt, int index, double width) { + void editCardWindow( + MzansiProfileProvider mzansiProfileProvider, + MzansiWalletProvider walletProvider, + BuildContext ctxt, + int index, + double width) { showDialog( context: context, barrierDismissible: false, @@ -144,6 +148,7 @@ class _BuildLoyaltyCardListState extends State { if (_formKey.currentState!.validate()) { int statusCode = await MIHMzansiWalletApis .updateLoyaltyCardAPICall( + walletProvider, mzansiProfileProvider.user!, widget.cardList[index].idloyalty_cards, widget.cardList[index].shop_name, @@ -211,7 +216,7 @@ class _BuildLoyaltyCardListState extends State { } void deleteCardWindow(MzansiProfileProvider mzansiProfileProvider, - BuildContext ctxt, int index) { + MzansiWalletProvider walletProvider, BuildContext ctxt, int index) { showDialog( context: context, barrierDismissible: false, @@ -221,6 +226,7 @@ class _BuildLoyaltyCardListState extends State { onTap: () async { int statusCode = await MIHMzansiWalletApis.deleteLoyaltyCardAPICall( + walletProvider, mzansiProfileProvider.user!, widget.cardList[index].idloyalty_cards, context, @@ -238,7 +244,7 @@ class _BuildLoyaltyCardListState extends State { } void addToFavCardWindow(MzansiProfileProvider mzansiProfileProvider, - BuildContext ctxt, int index) { + MzansiWalletProvider walletProvider, BuildContext ctxt, int index) { showDialog( context: context, barrierDismissible: false, @@ -270,6 +276,7 @@ class _BuildLoyaltyCardListState extends State { onPressed: () async { int statusCode = await MIHMzansiWalletApis.updateLoyaltyCardAPICall( + walletProvider, mzansiProfileProvider.user!, widget.cardList[index].idloyalty_cards, widget.cardList[index].shop_name, @@ -283,6 +290,7 @@ class _BuildLoyaltyCardListState extends State { context.pop(); context.pop(); await MIHMzansiWalletApis.getFavouriteLoyaltyCards( + walletProvider, mzansiProfileProvider.user!.app_id, context, ); @@ -323,7 +331,7 @@ class _BuildLoyaltyCardListState extends State { } void removeFromFavCardWindow(MzansiProfileProvider mzansiProfileProvider, - BuildContext ctxt, int index) { + MzansiWalletProvider walletProvider, BuildContext ctxt, int index) { showDialog( context: context, barrierDismissible: false, @@ -355,6 +363,7 @@ class _BuildLoyaltyCardListState extends State { onPressed: () async { int statusCode = await MIHMzansiWalletApis.updateLoyaltyCardAPICall( + walletProvider, mzansiProfileProvider.user!, widget.cardList[index].idloyalty_cards, widget.cardList[index].shop_name, @@ -368,6 +377,7 @@ class _BuildLoyaltyCardListState extends State { context.pop(); context.pop(); await MIHMzansiWalletApis.getFavouriteLoyaltyCards( + walletProvider, mzansiProfileProvider.user!.app_id, context, ); @@ -396,8 +406,8 @@ class _BuildLoyaltyCardListState extends State { ); } - void viewCardWindow( - MzansiProfileProvider mzansiProfileProvider, int index, double width) { + void viewCardWindow(MzansiProfileProvider mzansiProfileProvider, + MzansiWalletProvider walletProvider, 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++) { @@ -441,12 +451,14 @@ class _BuildLoyaltyCardListState extends State { if (widget.cardList[index].favourite == "") { addToFavCardWindow( mzansiProfileProvider, + walletProvider, context, index, ); } else { removeFromFavCardWindow( mzansiProfileProvider, + walletProvider, context, index, ); @@ -476,6 +488,7 @@ class _BuildLoyaltyCardListState extends State { }); editCardWindow( mzansiProfileProvider, + walletProvider, context, index, width, @@ -501,6 +514,7 @@ class _BuildLoyaltyCardListState extends State { onTap: () { deleteCardWindow( mzansiProfileProvider, + walletProvider, context, index, ); @@ -705,9 +719,11 @@ class _BuildLoyaltyCardListState extends State { // final double width = size.width; //final double height = size.height; if (widget.cardList.isNotEmpty) { - return Consumer( + return Consumer2( builder: (BuildContext context, - MzansiProfileProvider mzansiProfileProvider, Widget? child) { + MzansiProfileProvider mzansiProfileProvider, + MzansiWalletProvider walletProvider, + Widget? child) { return GridView.builder( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, @@ -732,6 +748,7 @@ class _BuildLoyaltyCardListState extends State { setScreenBrightness(1.0); viewCardWindow( mzansiProfileProvider, + walletProvider, 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 b1e69c35..d97ded85 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 @@ -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/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_packages/mzansi_wallet/components/mih_card_display.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; @@ -72,9 +73,6 @@ class _MihAddCardWindowState extends State { child: MihButton( onPressed: () { context.pop(); - context.goNamed( - 'mzansiWallet', - ); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -141,9 +139,11 @@ class _MihAddCardWindowState extends State { padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" ? EdgeInsets.symmetric(horizontal: width * 0.05) : EdgeInsets.symmetric(horizontal: width * 0), - child: Consumer( + child: Consumer2( builder: (BuildContext context, - MzansiProfileProvider mzansiProfileProvider, Widget? child) { + MzansiProfileProvider mzansiProfileProvider, + MzansiWalletProvider walletProvider, + Widget? child) { return Column( children: [ MihForm( @@ -158,9 +158,7 @@ class _MihAddCardWindowState extends State { return MihValidationServices().isEmpty(value); }, requiredText: true, - dropdownOptions: const [ - "+More", - "Apple Tree", + dropdownOptions: const [ "+More", "Apple Tree", "Auchan", @@ -206,7 +204,7 @@ class _MihAddCardWindowState extends State { "Total Energies", "Toys R Us", "Woermann Brock", - "Woolworths" + "Woolworths", ], ), ValueListenableBuilder( @@ -306,6 +304,7 @@ class _MihAddCardWindowState extends State { } else { int statusCode = await MIHMzansiWalletApis .addLoyaltyCardAPICall( + walletProvider, mzansiProfileProvider.user!, mzansiProfileProvider.user!.app_id, _shopController.text, @@ -317,7 +316,7 @@ class _MihAddCardWindowState extends State { ); if (statusCode == 201) { context.pop(); - KenLogger.error("Card Added Successfully"); + KenLogger.success("Card Added Successfully"); successPopUp( "Successfully Added Card", "The loyalty card has been added to your favourites.", diff --git a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart index bfc58d34..e744a248 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart @@ -25,24 +25,31 @@ class _MihWalletState extends State { bool isLoading = true; Future setLoyaltyCards( - MzansiProfileProvider mzansiProfileProvider) async { + MzansiProfileProvider mzansiProfileProvider, + MzansiWalletProvider walletProvider, + ) async { await MIHMzansiWalletApis.getLoyaltyCards( - mzansiProfileProvider.user!.app_id, context); + walletProvider, mzansiProfileProvider.user!.app_id, context); } Future setFavouritesCards( - MzansiProfileProvider mzansiProfileProvider) async { + MzansiProfileProvider mzansiProfileProvider, + MzansiWalletProvider walletProvider, + ) async { await MIHMzansiWalletApis.getFavouriteLoyaltyCards( - mzansiProfileProvider.user!.app_id, context); + walletProvider, mzansiProfileProvider.user!.app_id, context); } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - var mzansiProfileProvider = context.read(); - await setLoyaltyCards(mzansiProfileProvider); - await setFavouritesCards(mzansiProfileProvider); + MzansiProfileProvider mzansiProfileProvider = + context.read(); + MzansiWalletProvider walletProvider = + context.read(); + await setLoyaltyCards(mzansiProfileProvider, walletProvider); + await setFavouritesCards(mzansiProfileProvider, walletProvider); context.read().loadBannerAd(); setState(() { isLoading = false; 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 089a382d..18f59a8f 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 @@ -29,19 +29,18 @@ class MihCards extends StatefulWidget { class _MihCardsState extends State { final TextEditingController cardSearchController = TextEditingController(); final FocusNode searchFocusNode = FocusNode(); - List listOfCards = []; final ValueNotifier> searchShopName = ValueNotifier([]); final MobileScannerController scannerController = MobileScannerController( detectionSpeed: DetectionSpeed.unrestricted, ); final boxFit = BoxFit.contain; - void searchShop() { + void searchShop(List allCards) { if (cardSearchController.text.isEmpty) { - searchShopName.value = listOfCards; + searchShopName.value = allCards; } else { List temp = []; - for (var item in listOfCards) { + for (var item in allCards) { if (item.shop_name .toLowerCase() .contains(cardSearchController.text.toLowerCase()) || @@ -130,24 +129,23 @@ class _MihCardsState extends State { @override void dispose() { - cardSearchController.removeListener(searchShop); + final walletProvider = context.read(); + cardSearchController.removeListener(() { + searchShop(walletProvider.loyaltyCards); + }); cardSearchController.dispose(); searchShopName.dispose(); searchFocusNode.dispose(); super.dispose(); } - void getLoyaltyCards(BuildContext context) async { - setState(() { - listOfCards = context.read().loyaltyCards; - }); - searchShop(); - } - @override void initState() { - getLoyaltyCards(context); - cardSearchController.addListener(searchShop); + final walletProvider = context.read(); + searchShopName.value = walletProvider.loyaltyCards; + cardSearchController.addListener(() { + searchShop(walletProvider.loyaltyCards); + }); super.initState(); } @@ -162,76 +160,89 @@ class _MihCardsState extends State { } Widget getBody(double width) { - return Stack( - children: [ - MihSingleChildScroll( - child: Column( - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: width / 20), - child: MihSearchBar( - controller: cardSearchController, - hintText: "Search Cards", - // prefixIcon: Icons.search, - prefixIcon: Icons.search, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - hintColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onPrefixIconTap: () { - // print("Search Icon Pressed: ${cardSearchController.text}"); - }, - searchFocusNode: searchFocusNode, - ), - ), - const SizedBox(height: 10), - Consumer( - builder: (context, mzansiWalletProvider, child) { - listOfCards = mzansiWalletProvider.loyaltyCards; - return ValueListenableBuilder>( - valueListenable: searchShopName, - builder: (context, filteredCards, child) { - return BuildLoyaltyCardList( - cardList: filteredCards, //listOfCards, - navIndex: 0, - favouritesMode: false, - searchText: cardSearchController, - ); - }); - }, - ), - ], - ), - ), - 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"), + return Consumer( + builder: (BuildContext context, MzansiWalletProvider walletProvider, + Widget? child) { + if (cardSearchController.text.isEmpty) { + searchShopName.value = walletProvider.loyaltyCards; + } else { + // Re-run search with updated card list + searchShop(walletProvider.loyaltyCards); + } + return Stack( + children: [ + MihSingleChildScroll( + child: Column( + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: cardSearchController, + hintText: "Search Cards", + // prefixIcon: Icons.search, + prefixIcon: Icons.search, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + hintColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onPrefixIconTap: () { + // print("Search Icon Pressed: ${cardSearchController.text}"); + }, + searchFocusNode: searchFocusNode, + ), ), - 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, + const SizedBox(height: 10), + ValueListenableBuilder>( + valueListenable: searchShopName, + builder: (context, filteredCards, child) { + return BuildLoyaltyCardList( + cardList: filteredCards, //listOfCards, + navIndex: 0, + favouritesMode: false, + searchText: cardSearchController, + ); + }, ), - backgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onTap: () { - addCardWindow(context, width); - }, - ) - ]), - ) - ], + ], + ), + ), + 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: "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, width); + }, + ) + ]), + ) + ], + ); + }, ); } } diff --git a/Frontend/lib/mih_services/mih_mzansi_wallet_services.dart b/Frontend/lib/mih_services/mih_mzansi_wallet_services.dart index 7dcdd4e1..1acf927b 100644 --- a/Frontend/lib/mih_services/mih_mzansi_wallet_services.dart +++ b/Frontend/lib/mih_services/mih_mzansi_wallet_services.dart @@ -1,14 +1,13 @@ 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/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'; import '../mih_components/mih_pop_up_messages/mih_success_message.dart'; import '../mih_config/mih_env.dart'; @@ -17,6 +16,7 @@ class MIHMzansiWalletApis { final baseAPI = AppEnviroment.baseApiUrl; static Future getLoyaltyCards( + MzansiWalletProvider walletProvider, String app_id, BuildContext context, ) async { @@ -26,7 +26,7 @@ class MIHMzansiWalletApis { Iterable l = jsonDecode(response.body); List myCards = List.from( l.map((model) => MIHLoyaltyCard.fromJson(model))); - context.read().setLoyaltyCards(cards: myCards); + walletProvider.setLoyaltyCards(cards: myCards); // return myCards; } else { throw Exception('failed to fatch loyalty cards'); @@ -34,6 +34,7 @@ class MIHMzansiWalletApis { } static Future getFavouriteLoyaltyCards( + MzansiWalletProvider walletProvider, String app_id, BuildContext context, ) async { @@ -44,7 +45,7 @@ class MIHMzansiWalletApis { Iterable l = jsonDecode(response.body); List myCards = List.from( l.map((model) => MIHLoyaltyCard.fromJson(model))); - context.read().setFavouriteCards(cards: myCards); + walletProvider.setFavouriteCards(cards: myCards); } // else { // throw Exception('failed to fatch loyalty cards'); @@ -60,6 +61,7 @@ class MIHMzansiWalletApis { /// /// Returns VOID (TRIGGERS NOTIGICATIOPN ON SUCCESS) static Future deleteLoyaltyCardAPICall( + MzansiWalletProvider walletProvider, AppUser signedInUser, int idloyalty_cards, BuildContext context, @@ -77,9 +79,7 @@ class MIHMzansiWalletApis { //print(response.statusCode); context.pop(); if (response.statusCode == 200) { - context - .read() - .deleteLoyaltyCard(cardId: idloyalty_cards); + walletProvider.deleteLoyaltyCard(cardId: idloyalty_cards); } return response.statusCode; // if (response.statusCode == 200) { @@ -111,6 +111,7 @@ class MIHMzansiWalletApis { /// /// Returns VOID (TRIGGERS SUCCESS pop up) static Future addLoyaltyCardAPICall( + MzansiWalletProvider walletProvider, AppUser signedInUser, String app_id, String shop_name, @@ -137,6 +138,10 @@ class MIHMzansiWalletApis { }), ); context.pop(); + KenLogger.success("Response: $response"); + if (response.statusCode == 201) { + await getLoyaltyCards(walletProvider, app_id, context); + } return response.statusCode; // if (response.statusCode == 201) { // // Navigator.pop(context); @@ -164,6 +169,7 @@ class MIHMzansiWalletApis { /// /// Returns VOID (TRIGGERS NOTIGICATIOPN ON SUCCESS) static Future updateLoyaltyCardAPICall( + MzansiWalletProvider walletProvider, AppUser signedInUser, int idloyalty_cards, String shopName, @@ -190,17 +196,17 @@ 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, - ), - ); + walletProvider.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 1329c8aba4368156404902353be9ca31b60261a5 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 3 Nov 2025 11:27:44 +0200 Subject: [PATCH 03/19] BUG: MIH Ad Display Strategy --- .../mih_package_components/mih_banner_ad.dart | 18 ++++++++ .../mih_providers/mih_banner_ad_provider.dart | 5 +++ .../calculator/mih_calculator.dart | 2 - .../package_tools/currency_exchange_rate.dart | 2 - .../calculator/package_tools/tip_calc.dart | 2 - .../package_tools/mine_sweeper_game.dart | 44 ++++++------------- .../builder/build_loyalty_card_list.dart | 6 +-- .../mzansi_wallet/mih_wallet.dart | 2 - .../package_tools/mih_cards.dart | 18 ++++---- 9 files changed, 47 insertions(+), 52 deletions(-) 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 8c52c32c..61abe627 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 @@ -12,10 +12,28 @@ class MihBannerAd extends StatefulWidget { } class _MihBannerAdState extends State { + @override + void dispose() { + super.dispose(); + } + + @override + void initState() { + super.initState(); + MihBannerAdProvider adProvider = context.read(); + WidgetsBinding.instance.addPostFrameCallback((_) { + adProvider.reset(); + adProvider.loadBannerAd(); + }); + } + @override Widget build(BuildContext context) { return Consumer( builder: (context, bannerAdProvider, child) { + if (!bannerAdProvider.isBannerAdLoaded) { + return SizedBox(); + } return Column( children: [ bannerAdProvider.bannerAd != null && 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 560fc91a..394bcbb4 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 @@ -28,6 +28,11 @@ class MihBannerAdProvider extends ChangeNotifier { } void loadBannerAd() { + if (bannerAd != null) { + bannerAd!.dispose(); + bannerAd = null; + isBannerAdLoaded = false; + } bannerAd = BannerAd( adUnitId: adUnitId, request: const AdRequest(), diff --git a/Frontend/lib/mih_packages/calculator/mih_calculator.dart b/Frontend/lib/mih_packages/calculator/mih_calculator.dart index e0ed5add..775a868e 100644 --- a/Frontend/lib/mih_packages/calculator/mih_calculator.dart +++ b/Frontend/lib/mih_packages/calculator/mih_calculator.dart @@ -2,7 +2,6 @@ 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_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'; @@ -29,7 +28,6 @@ class _MIHCalculatorState extends State { void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - context.read().loadBannerAd(); await getCurrencyCodeList(); }); } 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 b0680632..6fabe709 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,7 +9,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_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_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'; @@ -67,7 +66,6 @@ class _CurrencyExchangeRateState extends State { fullscreen: false, windowTitle: "Calculation Results", onWindowTapClose: () { - context.read().loadBannerAd(); Navigator.pop(context); }, windowBody: Column( 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 229dbd1e..58583291 100644 --- a/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart +++ b/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart @@ -1,6 +1,5 @@ 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'; @@ -99,7 +98,6 @@ class _TipCalcState extends State { fullscreen: false, windowTitle: "Calculation Results", onWindowTapClose: () { - context.read().loadBannerAd(); Navigator.pop(context); }, windowBody: Column( 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 3facf977..59632f77 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 @@ -13,7 +13,6 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ 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'; @@ -124,8 +123,9 @@ class _MineSweeperGameState extends State { return '$hoursStr:$minutesStr:$secondsStr:$centiStr'; } - void showStartGameWindow(MihMineSweeperProvider mihMineSweeperProvider, - MihBannerAdProvider addProvider) { + void showStartGameWindow( + MihMineSweeperProvider mihMineSweeperProvider, + ) { // easy - 10 * 10 & 15 bombs // Intermediate - 10 * 15 & 23 bombs // Hard - 10 * 20 & 30 bombs @@ -134,7 +134,6 @@ class _MineSweeperGameState extends State { builder: (context) { return MihMineSweeperStartGameWindow( onPressed: () { - addProvider.loadBannerAd(); resetTimer(); mihMineSweeperProvider .setDifficulty(mihMineSweeperProvider.difficulty); @@ -241,12 +240,8 @@ class _MineSweeperGameState extends State { } } - Future handleTap( - MzansiProfileProvider profileProvider, - MihMineSweeperProvider mihMineSweeperProvider, - MihBannerAdProvider adProvider, - int r, - int c) async { + Future handleTap(MzansiProfileProvider profileProvider, + MihMineSweeperProvider mihMineSweeperProvider, int r, int c) async { if (isGameOver || board[r][c].isOpened || board[r][c].isFlagged) { return; } @@ -304,8 +299,7 @@ class _MineSweeperGameState extends State { MihButton( onPressed: () { context.pop(); - showStartGameWindow( - mihMineSweeperProvider, adProvider); + showStartGameWindow(mihMineSweeperProvider); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == @@ -364,7 +358,7 @@ class _MineSweeperGameState extends State { squaresLeft--; } // 3. Check for win - _checkWinCondition(profileProvider, mihMineSweeperProvider, adProvider); + _checkWinCondition(profileProvider, mihMineSweeperProvider); // Update the UI setState(() {}); } @@ -383,7 +377,6 @@ class _MineSweeperGameState extends State { Future _checkWinCondition( MzansiProfileProvider profileProvider, MihMineSweeperProvider mihMineSweeperProvider, - MihBannerAdProvider adProvider, ) async { // Game is won if all non-mine squares are opened. if (squaresLeft <= mihMineSweeperProvider.totalMines) { @@ -450,7 +443,7 @@ class _MineSweeperGameState extends State { MihButton( onPressed: () { context.pop(); - showStartGameWindow(mihMineSweeperProvider, adProvider); + showStartGameWindow(mihMineSweeperProvider); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == @@ -558,13 +551,9 @@ class _MineSweeperGameState extends State { } Widget getBody() { - return Consumer3( - builder: (BuildContext context, - MzansiProfileProvider profileProvider, - MihMineSweeperProvider mihMineSweeperProvider, - MihBannerAdProvider adProvider, - Widget? child) { + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + MihMineSweeperProvider mihMineSweeperProvider, Widget? child) { return Column( children: [ Expanded( @@ -725,12 +714,8 @@ class _MineSweeperGameState extends State { return MineTile( square: board[r][c], - onTap: () => handleTap( - profileProvider, - mihMineSweeperProvider, - adProvider, - r, - c), + onTap: () => handleTap(profileProvider, + mihMineSweeperProvider, r, c), onLongPress: () => handleLongPress(r, c), ); }, @@ -794,8 +779,7 @@ class _MineSweeperGameState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - showStartGameWindow( - mihMineSweeperProvider, adProvider); + showStartGameWindow(mihMineSweeperProvider); }, ), ]), 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 11cdb53c..7110a464 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,7 +6,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_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'; @@ -522,7 +521,6 @@ class _BuildLoyaltyCardListState extends State { ), ], onWindowTapClose: () { - context.read().loadBannerAd(); resetScreenBrightness(); context.pop(); }, @@ -584,9 +582,7 @@ class _BuildLoyaltyCardListState extends State { ), ), SizedBox(height: 10), - Consumer(builder: (context, bannerAdDisplay, child) { - return MihBannerAd(); - }), + 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 e744a248..1d56e1db 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart @@ -3,7 +3,6 @@ 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_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'; @@ -50,7 +49,6 @@ class _MihWalletState extends State { context.read(); await setLoyaltyCards(mzansiProfileProvider, walletProvider); await setFavouritesCards(mzansiProfileProvider, walletProvider); - context.read().loadBannerAd(); setState(() { isLoading = false; }); 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 18f59a8f..65abd81b 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 @@ -34,6 +34,8 @@ class _MihCardsState extends State { detectionSpeed: DetectionSpeed.unrestricted, ); final boxFit = BoxFit.contain; + late MzansiWalletProvider _walletProvider; + late VoidCallback _searchListener; void searchShop(List allCards) { if (cardSearchController.text.isEmpty) { @@ -129,10 +131,7 @@ class _MihCardsState extends State { @override void dispose() { - final walletProvider = context.read(); - cardSearchController.removeListener(() { - searchShop(walletProvider.loyaltyCards); - }); + cardSearchController.removeListener(_searchListener); cardSearchController.dispose(); searchShopName.dispose(); searchFocusNode.dispose(); @@ -141,11 +140,12 @@ class _MihCardsState extends State { @override void initState() { - final walletProvider = context.read(); - searchShopName.value = walletProvider.loyaltyCards; - cardSearchController.addListener(() { - searchShop(walletProvider.loyaltyCards); - }); + _walletProvider = context.read(); + _searchListener = () { + searchShop(_walletProvider.loyaltyCards); + }; + searchShopName.value = _walletProvider.loyaltyCards; + cardSearchController.addListener(_searchListener); super.initState(); } From c0d152002c3b01fd59349dec4562500fb7bed55e Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 3 Nov 2025 11:30:46 +0200 Subject: [PATCH 04/19] QOL: Change reset game to start new game --- .../mine_sweeper/package_tools/mine_sweeper_game.dart | 4 +--- 1 file changed, 1 insertion(+), 3 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 59632f77..5abe891b 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 @@ -763,9 +763,7 @@ class _MineSweeperGameState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), - label: board.isEmpty && squaresLeft < 0 - ? "Start Game" - : "Reset Game", + label: "Start New Game", labelBackgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), From 429e91b6381f3b987de538e5bd0d68b303549f78 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 3 Nov 2025 13:12:16 +0200 Subject: [PATCH 05/19] QOL: update guide --- .../package_tools/mine_sweeper_game.dart | 2 +- .../mine_sweeper_quick_start_guide.dart | 1066 ++++++++++++----- 2 files changed, 799 insertions(+), 269 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 5abe891b..c701be22 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 @@ -753,7 +753,7 @@ class _MineSweeperGameState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - mihMineSweeperProvider.setToolIndex(2); + mihMineSweeperProvider.setToolIndex(3); }, ), SpeedDialChild( 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 2bd762c7..6e4144c0 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 @@ -14,163 +14,821 @@ class MineSweeperQuickStartGuide extends StatefulWidget { class _MineSweeperQuickStartGuideState extends State { - Widget _buildSectionTitle(String title) { - return Text( - title, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ); - } + double titleSize = 22.0; + double subtitleSize = 20.0; + double pointsSize = 18.0; - Widget _buildSubSectionTitle(String title) { - return Text( - title, - style: TextStyle( - fontSize: 17, - fontWeight: FontWeight.w600, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + Widget sectionOne() { + return Container( + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode != "Darl"), + borderRadius: BorderRadius.circular(15), ), - ); - } - - Widget _buildRulePoint({ - required String title, - required List points, - required Color color, - }) { - return Padding( - padding: - const EdgeInsets.only(left: 8.0, right: 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, + child: Padding( + padding: const EdgeInsets.all(15.0), + child: Column( + children: [ + // Title + Text( + "1. Two Main Actions\n(Your Controls)", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: titleSize, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), ), - ), - ...points - .map((point) => Padding( - padding: const EdgeInsets.only(left: 10.0), - child: Text( - '• $point', - style: TextStyle( - fontSize: 16, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - )) - .toList(), - ], - ), - ); - } - - Widget _buildNumberClue(String clue, String explanation) { - return Padding( - padding: const EdgeInsets.only(left: 8.0, right: 8.0, bottom: 4.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('• ', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), - Expanded( - child: RichText( + const SizedBox(height: 8), + //Part One + RichText( text: TextSpan( - style: TextStyle( - fontSize: 16, - color: MihColors.getOrangeColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark")), children: [ TextSpan( - text: 'If you see a $clue: ', - style: const TextStyle(fontWeight: FontWeight.bold)), - TextSpan(text: explanation), + text: 'Quick Tap (or Click): This is the Dig action.', + style: TextStyle( + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: subtitleSize, + ), + ), ], ), ), - ), - ], - ), - ); - } - - Widget _buildStrategyPoint(String title, String explanation, - {bool isAction = false}) { - return Padding( - padding: const EdgeInsets.only(right: 8.0, left: 8.0, bottom: 4.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - text: TextSpan( - style: TextStyle( - fontSize: 16, - color: MihColors.getPrimaryColor( - 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"), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.topLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '• Goal:', + style: TextStyle( + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: ' To uncover a square and see a number clue.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], ), ), - TextSpan(text: isAction ? ' $explanation' : ': $explanation'), - ], + ), ), - ), - ], + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.centerLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '• Risk:', + style: TextStyle( + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: ' If you click a mine, the game ends!', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 8), + //Part Two + RichText( + text: TextSpan( + children: [ + TextSpan( + text: + 'Tap and Hold (or Long Press): This is the Flag action (🚩).', + style: TextStyle( + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: subtitleSize, + ), + ), + ], + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.topLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '• Goal:', + style: TextStyle( + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: ' To safely mark a square that you are', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + TextSpan( + text: ' certain', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: ' is a mine.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.centerLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '• Risk:', + style: TextStyle( + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + ' Accidental placement of flags will cause confusion.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.centerLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '• Benefit:', + style: TextStyle( + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + ' You cannot accidentally click a square that is flagged.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + ], + ), ), ); } - 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('• ', + Widget sectionTwo() { + return Container( + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode != "Darl"), + borderRadius: BorderRadius.circular(15), + ), + child: Padding( + padding: const EdgeInsets.all(15.0), + child: Column( + children: [ + // Title + Text( + "2. The Golden Rule\n(Reading the Numbers)", + textAlign: TextAlign.center, style: TextStyle( - fontSize: 18, - color: MihColors.getBronze( - MzansiInnovationHub.of(context)!.theme.mode != "Dark"), - fontWeight: FontWeight.bold)), - Expanded( - child: RichText( + fontSize: titleSize, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + const SizedBox(height: 8), + //Part One + RichText( text: TextSpan( - style: TextStyle( - fontSize: 16, - color: MihColors.getBronze( - MzansiInnovationHub.of(context)!.theme.mode == "Dark")), children: [ TextSpan( - text: title, - style: const TextStyle(fontWeight: FontWeight.bold)), - TextSpan(text: explanation), + text: + 'The number tells you exactly how many mines are touching that square (including sides and corners).', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: subtitleSize, + ), + ), ], ), ), - ), - ], + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.topLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: "• If you see a Blank Space (a '0'):", + style: TextStyle( + color: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: " Zero (0) ", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + ' mines are touching it. All surrounding squares are safe, and the game will open them for you automatically.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.centerLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: "• If you see a '1':", + style: TextStyle( + color: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: ' Only ', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + TextSpan( + text: 'one', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + ' mine is touching this square. You must find and flag that single mine.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.topLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: "• If you see a '3':", + style: TextStyle( + color: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: " Three ", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + 'mines are touching this square. You must find and flag all three.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + ], + ), + ), + ); + } + + Widget sectionThree() { + return Container( + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode != "Darl"), + borderRadius: BorderRadius.circular(15), + ), + child: Padding( + padding: const EdgeInsets.all(15.0), + child: Column( + children: [ + // Title + Text( + "3. The Winning Strategy\n(The Deduction Loop)", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: titleSize, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + const SizedBox(height: 8), + //Part One + RichText( + text: TextSpan( + children: [ + TextSpan( + 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( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: subtitleSize, + ), + ), + ], + ), + ), + const SizedBox(height: 8), + RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'A. Find the Mines (Where to Flag 🚩)', + style: TextStyle( + color: MihColors.getPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: subtitleSize, + ), + ), + ], + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.topLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '• Goal:', + style: TextStyle( + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + ' Look for a number that only has one choice for a mine. e.g. If a \'1\' is touching only one hidden square, that hidden square', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + TextSpan( + text: ' must ', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: 'be the mine.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.centerLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '• Action:', + style: TextStyle( + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: ' Tap and Hold to place a', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + TextSpan( + text: ' Flag ', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: 'on the square you are sure is a mine.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 8), + //Part Two + RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'B. Find the Safe Squares (Where to Dig)', + style: TextStyle( + color: MihColors.getPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: subtitleSize, + ), + ), + ], + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.topLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '• Goal:', + style: TextStyle( + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + ' Look for a number that has been \'satisfied\' by your flags. e.g. You see a \'2\' and you have already placed two 🚩 flags touching it. The \'2\' is satisfied.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.centerLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '• Action:', + style: TextStyle( + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + ' Quick Tap any of the remaining hidden squares touching that \'satisfied\' number. They', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + TextSpan( + text: ' must be safe ', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + 'because the mine requirement has already been met.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + ], + ), + ), + ); + } + + Widget sectionFour() { + return Container( + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode != "Darl"), + borderRadius: BorderRadius.circular(15), + ), + child: Padding( + padding: const EdgeInsets.all(15.0), + child: Column( + children: [ + // Title + Text( + "✨ Key Beginner Tips", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: titleSize, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.topLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: "• Start on the Edges and Corners: ", + style: TextStyle( + color: MihColors.getBronze( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + 'Numbers on the edge or corner of the board are easier to solve because they have fewer surrounding squares to check.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Align( + alignment: Alignment.topLeft, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: "• Don't Guess: ", + style: TextStyle( + color: MihColors.getBronze( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + fontSize: pointsSize, + ), + ), + TextSpan( + text: + '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.', + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.normal, + fontSize: pointsSize, + ), + ), + ], + ), + ), + ), + ), + ], + ), ), ); } @@ -202,146 +860,18 @@ class _MineSweeperQuickStartGuideState 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), + style: TextStyle(fontSize: 18), ), // const Divider(height: 30), const SizedBox(height: 15), - // --- 1. Two Main Actions --- - 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), - ], - ), - ), + sectionOne(), const SizedBox(height: 15), - // --- 2. The Golden Rule: Reading the Numbers --- - 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), - ], - ), - ), + sectionTwo(), const SizedBox(height: 15), - // --- 3. The Winning Strategy --- - 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), - ], - ), - ), + sectionThree(), + const SizedBox(height: 15), + sectionFour(), const SizedBox(height: 15), - // --- Key Beginner Tip --- - 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), - ], - ), - ), ], ), ), From a561f4fa5f1afea028a6b434670023f5cfd0601f Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 3 Nov 2025 19:28:52 +0200 Subject: [PATCH 06/19] BUG: Set up patient flow --- .../package_tiles/patient_profile_tile.dart | 10 +++++++--- .../patient_manager/pat_profile/patient_profile.dart | 5 +---- 2 files changed, 8 insertions(+), 7 deletions(-) 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 1fe19f93..13c6ba82 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 @@ -31,9 +31,13 @@ class _PatientProfileTileState extends State { PatientManagerProvider patientManagerProvider = context.read(); patientManagerProvider.setPersonalMode(true); - context.goNamed( - 'patientProfile', - ); + if (patientManagerProvider.selectedPatient != null) { + context.goNamed( + 'patientProfile', + ); + } else { + context.goNamed("patientProfileSetup"); + } // Navigator.of(context).pushNamed( // '/patient-profile', // arguments: widget.arguments, 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 806ff6d7..d0f68be1 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 @@ -39,10 +39,7 @@ class _PatientProfileState extends State { await MihPatientServices() .getPatientDetails(app_id, patientManagerProvider); } - if (patientManagerProvider.selectedPatient == null) { - // go to set up patient package - context.goNamed("patientProfileSetup"); - } else { + if (patientManagerProvider.selectedPatient != null) { await MihPatientServices() .getPatientConsultationNotes(patientManagerProvider); await MihPatientServices().getPatientDocuments(patientManagerProvider); From 0cabe11ab7d0f365f9d7de2c945cbf2cdf9c2a30 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 4 Nov 2025 10:15:34 +0200 Subject: [PATCH 07/19] BUG: Business Profile Tool Transitions --- Frontend/lib/mih_config/mih_go_router.dart | 9 +-- ...ness_profile.dart => busines_profile.dart} | 58 ++++++++++--------- .../package_tools/mih_business_qr_code.dart | 29 ++++++---- .../package_tools/mih_business_reviews.dart | 30 ++++++---- .../mih_business_user_search.dart | 9 ++- .../package_tools/mih_my_business_team.dart | 33 ++--------- .../package_tools/mih_my_business_user.dart | 24 ++++---- .../mzansi_wallet/mih_wallet.dart | 1 - 8 files changed, 93 insertions(+), 100 deletions(-) rename Frontend/lib/mih_packages/mzansi_profile/business_profile/{mzansi_business_profile.dart => busines_profile.dart} (82%) diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index 71de50cc..685ce86b 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -17,7 +17,7 @@ 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'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/busines_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/mzansi_set_up_business_profile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart'; @@ -190,9 +190,10 @@ class MihGoRouter { }); return const SizedBox.shrink(); } - return MzansiBusinessProfile( - key: UniqueKey(), - ); + return BusinesProfile(); + // return MzansiBusinessProfile( + // key: UniqueKey(), + // ); }, ), GoRoute( diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/busines_profile.dart similarity index 82% rename from Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart rename to Frontend/lib/mih_packages/mzansi_profile/business_profile/busines_profile.dart index 69dd98ea..fbf3cbb7 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/busines_profile.dart @@ -1,34 +1,45 @@ +import 'package:flutter/material.dart'; import 'package:go_router/go_router.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_providers/mzansi_profile_provider.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:mzansi_innovation_hub/mih_services/mih_business_employee_services.dart'; import 'package:provider/provider.dart'; -class MzansiBusinessProfile extends StatefulWidget { - const MzansiBusinessProfile({ - super.key, - }); +class BusinesProfile extends StatefulWidget { + const BusinesProfile({super.key}); @override - State createState() => _MzansiBusinessProfileState(); + State createState() => _BusinesProfileState(); } -class _MzansiBusinessProfileState extends State { +class _BusinesProfileState extends State { + Future initialiseBusinessData() async { + MzansiProfileProvider profileProvider = + context.read(); + await MihBusinessEmployeeServices() + .fetchEmployees(profileProvider, context); + } + + @override + void initState() { + super.initState(); + initialiseBusinessData(); + } + @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); @@ -45,7 +56,6 @@ class _MzansiBusinessProfileState extends State { 'mihHome', ); FocusScope.of(context).unfocus(); - context.read().setBusinessIndex(0); }, ); } @@ -79,22 +89,6 @@ class _MzansiBusinessProfileState extends State { ); } - List getToolBody() { - List toolBodies = [ - MihBusinessDetails(), - MihMyBusinessUser(), - MihMyBusinessTeam(), - MihBusinessUserSearch(), - MihBusinessReviews( - business: context.watch().business!), - MihBusinessQrCode( - business: context.watch().business!, - // startUpSearch: "", - ), - ]; - return toolBodies; - } - List getToolTitle() { List toolTitles = [ "Profile", @@ -106,4 +100,16 @@ class _MzansiBusinessProfileState extends State { ]; return toolTitles; } + + List getToolBody() { + List toolBodies = [ + MihBusinessDetails(), + MihMyBusinessUser(), + MihMyBusinessTeam(), + MihBusinessUserSearch(), + MihBusinessReviews(business: null), + MihBusinessQrCode(business: null), + ]; + return toolBodies; + } } 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 268c768f..109de674 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 @@ -14,22 +14,22 @@ 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_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_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_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:provider/provider.dart'; import 'package:screenshot/screenshot.dart'; import 'package:share_plus/share_plus.dart'; import 'package:supertokens_flutter/supertokens.dart'; class MihBusinessQrCode extends StatefulWidget { - final Business business; - // final String? startUpSearch; + final Business? business; const MihBusinessQrCode({ super.key, required this.business, - // required this.startUpSearch, }); @override @@ -38,6 +38,7 @@ class MihBusinessQrCode extends StatefulWidget { class _MihBusinessQrCodeState extends State { late Future futureImageUrl; + late Business business; PlatformFile? file; late String qrCodedata; int qrSize = 500; @@ -66,14 +67,14 @@ class _MihBusinessQrCodeState extends State { .substring(2, 8); // KenLogger.warning(bgColor); String encodedData = - Uri.encodeComponent("$qrCodedata${widget.business.business_id}"); + Uri.encodeComponent("$qrCodedata${business.business_id}"); return "https://api.qrserver.com/v1/create-qr-code/?data=$encodedData&size=${qrSize}x${qrSize}&bgcolor=$bgColor&color=$color"; } Future saveImage(Uint8List imageBytes) async { final String filename = - "${widget.business.Name}_QR_Code_${DateTime.now().millisecondsSinceEpoch}.png"; + "${business.Name}_QR_Code_${DateTime.now().millisecondsSinceEpoch}.png"; if (kIsWeb) { await FileSaver.instance.saveFile( name: filename, @@ -241,7 +242,7 @@ class _MihBusinessQrCodeState extends State { ), FittedBox( child: Text( - widget.business.Name, + business.Name, style: TextStyle( fontSize: 35, fontWeight: FontWeight.bold, @@ -253,7 +254,7 @@ class _MihBusinessQrCodeState extends State { ), FittedBox( child: Text( - widget.business.type, + business.type, style: TextStyle( fontSize: 20, fontWeight: FontWeight.w600, @@ -335,9 +336,15 @@ class _MihBusinessQrCodeState extends State { @override void initState() { super.initState(); + MzansiProfileProvider profileProvider = + context.read(); + if (widget.business != null) { + business = widget.business!; + } else { + business = profileProvider.business!; + } _checkUserSession(); - futureImageUrl = - MihFileApi.getMinioFileUrl(widget.business.logo_path, context); + futureImageUrl = MihFileApi.getMinioFileUrl(business.logo_path, context); qrCodedata = "${AppEnviroment.baseAppUrl}/business-profile/view?business_id="; } @@ -418,8 +425,8 @@ class _MihBusinessQrCodeState extends State { onTap: () { shareMIHLink( context, - "Check out ${widget.business.Name} on the MIH app", - "$qrCodedata${widget.business.business_id}", + "Check out ${business.Name} on the MIH app", + "$qrCodedata${business.business_id}", ); }, ), 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 42f9f06a..f2f34dbd 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 @@ -5,12 +5,14 @@ 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_icons.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_review_business_window.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services.dart'; +import 'package:provider/provider.dart'; class MihBusinessReviews extends StatefulWidget { - final Business business; + final Business? business; const MihBusinessReviews({ super.key, required this.business, @@ -21,15 +23,19 @@ class MihBusinessReviews extends StatefulWidget { } class _MihBusinessReviewsState extends State { - // late Future> _reviews; + late Business business; - // @override - // void initState() { - // super.initState(); - // _reviews = MihMzansiDirectoryServices().getAllReviewsofBusiness( - // widget.businessId, - // ); - // } + @override + void initState() { + super.initState(); + MzansiProfileProvider profileProvider = + context.read(); + if (widget.business != null) { + business = widget.business!; + } else { + business = profileProvider.business!; + } + } void onReviewTap(BusinessReview? businessReview, double width) { // showDialog(context: context, builder: (context)=> ) @@ -37,7 +43,7 @@ class _MihBusinessReviewsState extends State { context: context, builder: (context) { return MihReviewBusinessWindow( - business: widget.business, + business: business, businessReview: businessReview, screenWidth: width, readOnly: true, @@ -52,7 +58,7 @@ class _MihBusinessReviewsState extends State { double screenWidth = MediaQuery.of(context).size.width; return FutureBuilder( future: MihMzansiDirectoryServices().getAllReviewsofBusiness( - widget.business.business_id, + business.business_id, ), builder: (context, asyncSnapshot) { if (asyncSnapshot.connectionState == ConnectionState.waiting) { @@ -93,7 +99,7 @@ class _MihBusinessReviewsState extends State { ), const SizedBox(height: 10), Text( - "No reviews yet, be the first the review ${widget.business.Name}", + "No reviews yet, be the first the review ${business.Name}", textAlign: TextAlign.center, overflow: TextOverflow.visible, style: TextStyle( 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 c2bc32fb..b614dffb 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 @@ -36,11 +36,9 @@ class _MihBusinessUserSearchState extends State { void submitUserForm(MzansiProfileProvider profileProvider) { if (searchController.text != "") { - setState(() { - userSearch = searchController.text; - hasSearchedBefore = true; - userSearchResults = fetchUsers(profileProvider, userSearch); - }); + userSearch = searchController.text; + hasSearchedBefore = true; + userSearchResults = fetchUsers(profileProvider, userSearch); } } @@ -192,6 +190,7 @@ class _MihBusinessUserSearchState extends State { searchController.clear(); userSearch = ""; }); + profileProvider.setUserearchResults(userSearchResults: []); }, searchFocusNode: _searchFocusNode, ), 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 3dc774a9..4583f888 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 @@ -7,7 +7,6 @@ import 'package:mzansi_innovation_hub/mih_config/mih_colors.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'; class MihMyBusinessTeam extends StatefulWidget { @@ -23,32 +22,11 @@ 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"); - // 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'); - // } + // void getEmployeeData(MzansiProfileProvider mzansiProfileProvider) { + // WidgetsBinding.instance.addPostFrameCallback((_) async { + // await MihBusinessEmployeeServices() + // .fetchEmployees(mzansiProfileProvider, context); + // }); // } Widget displayEmployeeList(List employeeList) { @@ -89,7 +67,6 @@ 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/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 8bc78d59..29049149 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 @@ -218,19 +218,17 @@ 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; - }); + 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 { diff --git a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart index 1d56e1db..91ffcd41 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart @@ -94,7 +94,6 @@ class _MihWalletState extends State { temp[const Icon(Icons.favorite)] = () { context.read().setToolIndex(1); }; - return MihPackageTools( tools: temp, selcetedIndex: context.watch().toolIndex, From 9cbdc849b1477b9f5872692c64baac5356266790 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 4 Nov 2025 10:17:38 +0200 Subject: [PATCH 08/19] BUG: back Nav from favourite business selection --- .../builders/build_favourite_businesses_list.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8f4e638d..94e2d5ae 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 @@ -47,7 +47,7 @@ class _BuildFavouriteBusinessesListState directoryProvider.setSelectedBusiness( business: widget.favouriteBusinesses[index]!, ); - context.goNamed( + context.pushNamed( 'businessProfileView', ); }, From 2a7e3e17ce007d7495363984e63abdaade761892 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 4 Nov 2025 11:00:29 +0200 Subject: [PATCH 09/19] BUG: Bookmarked businesses data load --- .../mih_business_profile_preview.dart | 5 +- .../mzansi_directory_provider.dart | 10 ++-- .../mzansi_directory/mzansi_directory.dart | 27 ++++++++++ .../mih_favourite_businesses.dart | 50 ++++--------------- .../mih_mzansi_directory_services.dart | 3 +- 5 files changed, 46 insertions(+), 49 deletions(-) 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 53683653..e8968df5 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 @@ -41,8 +41,6 @@ class _MihBusinessProfilePreviewState extends State { @override void initState() { super.initState(); - futureImageUrl = - MihFileApi.getMinioFileUrl(widget.business.logo_path, context); } @override @@ -54,7 +52,8 @@ class _MihBusinessProfilePreviewState extends State { return Row( children: [ FutureBuilder( - future: futureImageUrl, + future: MihFileApi.getMinioFileUrl( + widget.business.logo_path, context), builder: (context, asyncSnapshot) { if (asyncSnapshot.connectionState == ConnectionState.done && asyncSnapshot.hasData) { 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 59f148bc..dc1f7db2 100644 --- a/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart @@ -10,7 +10,7 @@ class MzansiDirectoryProvider extends ChangeNotifier { String userLocation; bool personalSearch; List bookmarkedBusinesses = []; - Map businessDetailsMap = {}; + List favouriteBusinessesList = []; List? searchedBusinesses; Business? selectedBusiness; List? searchedUsers; @@ -32,7 +32,6 @@ class MzansiDirectoryProvider extends ChangeNotifier { userLocation = "Unknown Location"; personalSearch = true; bookmarkedBusinesses = []; - businessDetailsMap = {}; searchedBusinesses = null; selectedBusiness = null; searchedUsers = null; @@ -62,13 +61,14 @@ class MzansiDirectoryProvider extends ChangeNotifier { notifyListeners(); } - void setFavouriteBusinesses({required List businesses}) { + void setBookmarkedeBusinesses( + {required List businesses}) { bookmarkedBusinesses = businesses; notifyListeners(); } - void setBusinessDetailsMap({required Map detailsMap}) { - businessDetailsMap = detailsMap; + void setFavouriteBusinesses({required List businesses}) { + favouriteBusinessesList = businesses; notifyListeners(); } diff --git a/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart b/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart index baa1dda3..5ddca512 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart @@ -1,13 +1,18 @@ import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.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: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_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_business_details_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_location_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services.dart'; import 'package:provider/provider.dart'; class MzansiDirectory extends StatefulWidget { @@ -31,11 +36,33 @@ class _MzansiDirectoryState extends State { }); } + Future getFavouriteBusinesses() async { + MzansiDirectoryProvider directoryProvider = + context.read(); + MzansiProfileProvider profileProvider = + context.read(); + await MihMzansiDirectoryServices().getAllUserBookmarkedBusiness( + profileProvider.user!.app_id, + directoryProvider, + ); + List favBus = []; + for (var bus in directoryProvider.bookmarkedBusinesses) { + await MihBusinessDetailsServices() + .getBusinessDetailsByBusinessId(bus.business_id) + .then((business) { + favBus.add(business!); + }); + } + KenLogger.success(favBus); + directoryProvider.setFavouriteBusinesses(businesses: favBus); + } + @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { initialiseGPSLocation(); + getFavouriteBusinesses(); }); } 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 eeb53ba0..55ac3cd5 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,5 +1,6 @@ import 'dart:async'; 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/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; @@ -7,11 +8,8 @@ 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_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:provider/provider.dart'; class MihFavouriteBusinesses extends StatefulWidget { @@ -31,39 +29,12 @@ class _MihFavouriteBusinessesState extends State { ValueNotifier([]); Timer? _debounce; - Future getAndMapAllBusinessDetailsForBookmarkedBusinesses( - MzansiProfileProvider mzansiProfileProvider, - MzansiDirectoryProvider directoryProvider, - ) async { - await MihMzansiDirectoryServices().getAllUserBookmarkedBusiness( - mzansiProfileProvider.user!.app_id, - directoryProvider, - ); - Map businessMap = {}; - List> detailFutures = []; - for (var item in directoryProvider.bookmarkedBusinesses) { - detailFutures.add(MihBusinessDetailsServices() - .getBusinessDetailsByBusinessId(item.business_id)); - } - List details = await Future.wait(detailFutures); - for (int i = 0; i < directoryProvider.bookmarkedBusinesses.length; i++) { - businessMap[directoryProvider.bookmarkedBusinesses[i].business_id] = - details[i]; - } - directoryProvider.setBusinessDetailsMap(detailsMap: businessMap); - _filterAndSetBusinesses(directoryProvider); - } - void _filterAndSetBusinesses(MzansiDirectoryProvider directoryProvider) { List businessesToDisplay = []; String query = businessSearchController.text.toLowerCase(); - for (var bookmarked in directoryProvider.bookmarkedBusinesses) { - if (bookmarked.business_name.toLowerCase().contains(query)) { - if (directoryProvider.businessDetailsMap - .containsKey(bookmarked.business_id)) { - businessesToDisplay.add( - directoryProvider.businessDetailsMap[bookmarked.business_id]); - } + for (var bus in directoryProvider.favouriteBusinessesList) { + if (bus.Name.toLowerCase().contains(query)) { + businessesToDisplay.add(bus); } } searchBookmarkedBusinesses.value = businessesToDisplay; @@ -82,13 +53,11 @@ class _MihFavouriteBusinessesState extends State { super.initState(); MzansiDirectoryProvider directoryProvider = context.read(); - MzansiProfileProvider mzansiProfileProvider = - context.read(); - - getAndMapAllBusinessDetailsForBookmarkedBusinesses( - mzansiProfileProvider, - directoryProvider, - ); + // getAndMapAllBusinessDetailsForBookmarkedBusinesses( + // mzansiProfileProvider, + // directoryProvider, + // ); + _filterAndSetBusinesses(directoryProvider); businessSearchController.addListener(() { if (_debounce?.isActive ?? false) { _debounce!.cancel(); @@ -214,6 +183,7 @@ class _MihFavouriteBusinessesState extends State { ), ); } + KenLogger.success(filteredBusinesses); return BuildFavouriteBusinessesList( favouriteBusinesses: filteredBusinesses, ); diff --git a/Frontend/lib/mih_services/mih_mzansi_directory_services.dart b/Frontend/lib/mih_services/mih_mzansi_directory_services.dart index 322615de..6b4bc076 100644 --- a/Frontend/lib/mih_services/mih_mzansi_directory_services.dart +++ b/Frontend/lib/mih_services/mih_mzansi_directory_services.dart @@ -166,7 +166,8 @@ class MihMzansiDirectoryServices { List favouriteBusinesses = List.from( l.map((model) => BookmarkedBusiness.fromJson(model))); - directoryProvider.setFavouriteBusinesses(businesses: favouriteBusinesses); + directoryProvider.setBookmarkedeBusinesses( + businesses: favouriteBusinesses); return favouriteBusinesses; } else if (response.statusCode == 404) { return []; From 11b6ec9edb897155498c9aafe8bbf9bf8a31dae0 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 4 Nov 2025 11:34:28 +0200 Subject: [PATCH 10/19] BUG: Update Appointment & Clear Coltrollers --- .../mih_providers/mih_calendar_provider.dart | 2 + .../builder/build_appointment_list.dart | 144 ++++++++++-------- .../calendar/package_tools/appointments.dart | 2 +- 3 files changed, 80 insertions(+), 68 deletions(-) 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 40265f45..fe4ee6b6 100644 --- a/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/appointment.dart'; class MihCalendarProvider extends ChangeNotifier { @@ -57,6 +58,7 @@ class MihCalendarProvider extends ChangeNotifier { int index = personalAppointments?.indexWhere((appointment) => appointment.idappointments == updatedAppointment.idappointments) ?? -1; + KenLogger.success("Edit Patient Index: $index"); if (index != -1) { personalAppointments?[index] = updatedAppointment; notifyListeners(); 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 d56ef908..32481014 100644 --- a/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart +++ b/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart @@ -3,7 +3,6 @@ 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'; @@ -59,6 +58,13 @@ class _BuildAppointmentListState extends State { late double width; late double height; + void clearControllers() { + widget.titleController.clear(); + widget.descriptionIDController.clear(); + widget.dateController.clear(); + widget.timeController.clear(); + } + double getPaddingSize() { if (MzansiInnovationHub.of(context)!.theme.screenType == "desktop") { return (width / 10); @@ -72,37 +78,41 @@ class _BuildAppointmentListState extends State { 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)); + + // SAFELY EXTRACT DATE AND TIME + String dateTimeString = appointmentList[index].date_time; + String timePart = ""; + String datePart = ""; + + if (dateTimeString.contains("T")) { + List parts = dateTimeString.split('T'); + datePart = parts[0]; + timePart = parts[1].substring(0, 5); + } else if (dateTimeString.contains(" ")) { + List parts = dateTimeString.split(' '); + datePart = parts[0]; + timePart = parts[1].substring(0, 5); } 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)); + // Fallback if format is unexpected + datePart = dateTimeString; + timePart = "00:00"; } + + String heading = + "$timePart - ${appointmentList[index].title.toUpperCase()}"; + String description = appointmentList[index].description; + + DateTime now = DateTime.now(); + int hourNow = int.parse(now.toString().split(' ')[1].substring(0, 2)); + String currentDate = + DateTime(now.year, now.month, now.day).toString().split(' ')[0]; + + int appointHour = int.parse(timePart.split(':')[0]); + Color appointmentColor = MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"); - if (date == appointDate) { + + if (currentDate == datePart) { if (appointHour < hourNow) { appointmentColor = MihColors.getGreyColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"); @@ -110,7 +120,7 @@ class _BuildAppointmentListState extends State { appointmentColor = MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"); } - } else if (DateTime.parse(appointDate).isBefore(DateTime.parse(date))) { + } else if (DateTime.parse(datePart).isBefore(DateTime.parse(currentDate))) { appointmentColor = MihColors.getGreyColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"); } @@ -138,15 +148,15 @@ class _BuildAppointmentListState extends State { ), ), onTap: () { + // SAFELY SET CONTROLLER VALUES setState(() { widget.titleController.text = appointmentList[index].title; widget.descriptionIDController.text = appointmentList[index].description; - widget.dateController.text = - appointmentList[index].date_time.split('T')[0]; - widget.timeController.text = - appointmentList[index].date_time.split('T')[1].substring(0, 5); + widget.dateController.text = datePart; + widget.timeController.text = timePart; }); + if (widget.inWaitingRoom == false) { appointmentDetailsWindow( mzansiProfileProvider, mihCalendarProvider, index, bodyWidth); @@ -214,10 +224,7 @@ class _BuildAppointmentListState extends State { ], onWindowTapClose: () { context.pop(); - widget.dateController.clear(); - widget.timeController.clear(); - widget.titleController.clear(); - widget.descriptionIDController.clear(); + clearControllers(); }, windowBody: Padding( padding: @@ -342,10 +349,7 @@ class _BuildAppointmentListState extends State { ], onWindowTapClose: () { context.pop(); - widget.dateController.clear(); - widget.timeController.clear(); - widget.titleController.clear(); - widget.descriptionIDController.clear(); + clearControllers(); }, windowBody: Padding( padding: @@ -591,6 +595,7 @@ class _BuildAppointmentListState extends State { List appointmentList = mzansiProfileProvider.personalHome ? mihCalendarProvider.personalAppointments! : mihCalendarProvider.businessAppointments!; + KenLogger.success("ersonalHome: ${mzansiProfileProvider.personalHome}"); if (mzansiProfileProvider.personalHome == true) { statusCode = await MihMzansiCalendarApis.updatePersonalAppointment( mzansiProfileProvider.user!, @@ -634,28 +639,30 @@ class _BuildAppointmentListState extends State { if (statusCode == 200) { context.pop(); context.pop(); - if (!widget.inWaitingRoom) { - KenLogger.warning("calendar route"); - context.goNamed( - "mihCalendar", - ); - } else { - KenLogger.warning("waiting room route"); - // GoRouter.of(context).refresh(); - context.goNamed( - 'mihHome', - ); - context.goNamed( - 'patientManager', - extra: PatManagerArguments( - mzansiProfileProvider.user!, - false, - mzansiProfileProvider.business, - mzansiProfileProvider.businessUser, - ), - ); - // context.pop(); - } + successPopUp("Successfully Updated Appointment", + "You appointment has been successfully updated."); + // if (!widget.inWaitingRoom) { + // KenLogger.warning("calendar route"); + // context.goNamed( + // "mihCalendar", + // ); + // } else { + // KenLogger.warning("waiting room route"); + // // GoRouter.of(context).refresh(); + // context.goNamed( + // 'mihHome', + // ); + // context.goNamed( + // 'patientManager', + // extra: PatManagerArguments( + // mzansiProfileProvider.user!, + // false, + // mzansiProfileProvider.business, + // mzansiProfileProvider.businessUser, + // ), + // ); + // // context.pop(); + // } } else { internetConnectionPopUp(); } @@ -724,6 +731,7 @@ class _BuildAppointmentListState extends State { child: MihButton( onPressed: () { context.pop(); + clearControllers(); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -805,15 +813,17 @@ class _BuildAppointmentListState extends State { MzansiProfileProvider mzansiProfileProvider, MihCalendarProvider mihCalendarProvider, Widget? child) { - List appointmentList = mzansiProfileProvider.personalHome - ? mihCalendarProvider.personalAppointments! - : mihCalendarProvider.businessAppointments!; + // 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, + itemCount: mzansiProfileProvider.personalHome + ? mihCalendarProvider.personalAppointments!.length + : mihCalendarProvider.businessAppointments!.length, itemBuilder: (context, index) { return displayAppointment( mzansiProfileProvider, mihCalendarProvider, index, width); diff --git a/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart b/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart index 1d198a82..26e3b59a 100644 --- a/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart +++ b/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart @@ -139,7 +139,7 @@ class _PatientAccessRequestState extends State { fullscreen: false, windowTitle: "Add Appointment", onWindowTapClose: () { - Navigator.of(context).pop(); + context.pop(); _appointmentDateController.clear(); _appointmentTimeController.clear(); _appointmentTitleController.clear(); From e318e038052dcc7cd06aaadc6455bde574be0c94 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 4 Nov 2025 11:36:04 +0200 Subject: [PATCH 11/19] QOL: Update build to 100 --- Frontend/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/pubspec.yaml b/Frontend/pubspec.yaml index 9969b895..1dfa6512 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.2+99 +version: 1.2.2+100 # version: 1.1.1+97 #--- Updated version for upgrader package testing environment: From 1a7293fc1281a617618f711d423e815dcb14540b Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 4 Nov 2025 11:43:47 +0200 Subject: [PATCH 12/19] deeplinking fix --- Frontend/android/app/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frontend/android/app/src/main/AndroidManifest.xml b/Frontend/android/app/src/main/AndroidManifest.xml index 6683a646..e2ba1525 100644 --- a/Frontend/android/app/src/main/AndroidManifest.xml +++ b/Frontend/android/app/src/main/AndroidManifest.xml @@ -59,8 +59,8 @@ - - + + +