From 6542f1c399dbabaa39188419dba01569a5160c31 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 13 Nov 2025 11:16:08 +0200 Subject: [PATCH 01/56] QOL: MIh WIndows ehnacement --- .../package_tools/package_tool_one.dart | 5 ++ .../mih_package_window.dart | 84 ++++++++----------- 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart b/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart index e72699bf..4cd410d5 100644 --- a/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart +++ b/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart @@ -96,6 +96,11 @@ class _PackageToolOneState extends State { builder: (context) { return MihPackageWindow( fullscreen: false, + borderOn: true, + foregroundColor: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + backgroundColor: MihColors.getBluishPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), windowTitle: "Test No Full", menuOptions: [ SpeedDialChild( diff --git a/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart b/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart index 157138f4..3654ae55 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; @@ -10,6 +11,9 @@ class MihPackageWindow extends StatefulWidget { final Widget windowBody; final List? menuOptions; final void Function() onWindowTapClose; + final Color? backgroundColor; + final Color? foregroundColor; + final bool? borderOn; final bool fullscreen; const MihPackageWindow({ super.key, @@ -18,6 +22,9 @@ class MihPackageWindow extends StatefulWidget { this.menuOptions, required this.onWindowTapClose, required this.windowBody, + this.borderOn, + this.backgroundColor, + this.foregroundColor, }); @override @@ -60,45 +67,22 @@ class _MihPackageWindowState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Container( - // color: Colors.white, - decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(25), // Optional: rounds the corners - boxShadow: const [ - BoxShadow( - color: Color.fromARGB( - 60, 0, 0, 0), // 0.2 opacity = 51 in alpha (255 * 0.2) - spreadRadius: -2, - blurRadius: 10, - offset: Offset(0, 5), - ), - ], + Padding( + padding: const EdgeInsets.only( + top: 5.0, + left: 5.0, ), - child: Padding( - padding: const EdgeInsets.only( - top: 2.0, - left: 5.0, - ), - child: SizedBox( - width: 40, - child: IconButton.filled( - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all( - MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark")), - ), - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - iconSize: 20, - onPressed: () { - widget.onWindowTapClose(); - }, - icon: const Icon( - Icons.close, - ), - ), + child: MihButton( + width: 40, + height: 40, + elevation: 10, + onPressed: widget.onWindowTapClose, + buttonColor: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Icon( + Icons.close, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ), ), @@ -112,8 +96,9 @@ class _MihPackageWindowState extends State { style: TextStyle( fontSize: windowTitleSize, fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + color: widget.foregroundColor ?? + MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ), ), @@ -122,7 +107,7 @@ class _MihPackageWindowState extends State { visible: (widget.menuOptions?.isNotEmpty ?? false), child: Padding( padding: const EdgeInsets.only( - top: 2.0, + top: 5.0, right: 5.0, ), child: SizedBox( @@ -170,13 +155,18 @@ class _MihPackageWindowState extends State { insetAnimationDuration: Durations.short1, child: Container( decoration: BoxDecoration( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - borderRadius: BorderRadius.circular(25.0), - border: Border.all( - color: MihColors.getSecondaryColor( + color: widget.backgroundColor ?? + MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 5.0), + borderRadius: BorderRadius.circular(25.0), + border: widget.borderOn == null || !widget.borderOn! + ? null + : Border.all( + color: widget.foregroundColor ?? + MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 5.0), ), child: widget.fullscreen ? Column( From 4fe544b35fe7ef75b1f892d9513be2031304ef20 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 13 Nov 2025 14:03:16 +0200 Subject: [PATCH 02/56] QOL: Patient Manager overhaul pt1 --- .../mih_package_window.dart | 139 ++-- .../patient_manager_provider.dart | 15 + .../lib/mih_packages/mih_home/mih_home.dart | 2 +- .../build_mih_patient_search_list.dart | 8 +- .../package_tiles/patient_profile_tile.dart | 2 + .../package_tools/patient_info.dart | 606 ++++++++---------- .../mih_access_controls_services.dart | 23 + .../lib/mih_services/mih_service_calls.dart | 569 ---------------- .../lib/mih_services/mih_user_services.dart | 22 +- 9 files changed, 399 insertions(+), 987 deletions(-) delete mode 100644 Frontend/lib/mih_services/mih_service_calls.dart diff --git a/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart b/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart index 3654ae55..21daa954 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart @@ -10,7 +10,7 @@ class MihPackageWindow extends StatefulWidget { final String windowTitle; final Widget windowBody; final List? menuOptions; - final void Function() onWindowTapClose; + final void Function()? onWindowTapClose; final Color? backgroundColor; final Color? foregroundColor; final bool? borderOn; @@ -67,25 +67,26 @@ class _MihPackageWindowState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Padding( - padding: const EdgeInsets.only( - top: 5.0, - left: 5.0, - ), - child: MihButton( - width: 40, - height: 40, - elevation: 10, - onPressed: widget.onWindowTapClose, - buttonColor: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Icon( - Icons.close, - color: MihColors.getPrimaryColor( + if (widget.onWindowTapClose != null) + Padding( + padding: const EdgeInsets.only( + top: 5.0, + left: 5.0, + ), + child: MihButton( + width: 40, + height: 40, + elevation: 10, + onPressed: widget.onWindowTapClose, + buttonColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Icon( + Icons.close, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), ), ), - ), Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 10.0), @@ -103,9 +104,8 @@ class _MihPackageWindowState extends State { ), ), ), - Visibility( - visible: (widget.menuOptions?.isNotEmpty ?? false), - child: Padding( + if (widget.menuOptions != null) + Padding( padding: const EdgeInsets.only( top: 5.0, right: 5.0, @@ -120,10 +120,6 @@ class _MihPackageWindowState extends State { ), ), ), - ), - // If no menu, add a SizedBox to keep alignment - if (!(widget.menuOptions?.isNotEmpty ?? false)) - const SizedBox(width: 40), ], ); } @@ -153,54 +149,59 @@ class _MihPackageWindowState extends State { ), insetAnimationCurve: Easing.emphasizedDecelerate, insetAnimationDuration: Durations.short1, - child: Container( - decoration: BoxDecoration( - color: widget.backgroundColor ?? - MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - borderRadius: BorderRadius.circular(25.0), - border: widget.borderOn == null || !widget.borderOn! - ? null - : Border.all( - color: widget.foregroundColor ?? - MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 5.0), - ), - child: widget.fullscreen - ? Column( - mainAxisSize: MainAxisSize.max, - children: [ - getHeader(), - const SizedBox(height: 5), - Expanded( - child: SingleChildScrollView(child: widget.windowBody)), - ], - ) - : Column( - mainAxisSize: MainAxisSize.min, - children: [ - getHeader(), - const SizedBox(height: 5), - Flexible( - child: Padding( - padding: EdgeInsets.only( - left: 25, - right: 25, - bottom: vertticalWindowPadding, - ), - child: ConstrainedBox( - constraints: BoxConstraints( - maxHeight: windowHeight * 0.85, - maxWidth: windowWidth * 0.85, + child: Material( + elevation: 10, + shadowColor: Colors.black, + color: widget.backgroundColor ?? + MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + borderRadius: BorderRadius.circular(25.0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(25.0), + border: widget.borderOn == null || !widget.borderOn! + ? null + : Border.all( + color: widget.foregroundColor ?? + MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 5.0), + ), + child: widget.fullscreen + ? Column( + mainAxisSize: MainAxisSize.max, + children: [ + getHeader(), + const SizedBox(height: 5), + Expanded( + child: SingleChildScrollView(child: widget.windowBody)), + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + children: [ + getHeader(), + const SizedBox(height: 5), + Flexible( + child: Padding( + padding: EdgeInsets.only( + left: 25, + right: 25, + bottom: vertticalWindowPadding, + ), + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: windowHeight * 0.85, + maxWidth: windowWidth * 0.85, + ), + child: MihSingleChildScroll(child: widget.windowBody), ), - child: MihSingleChildScroll(child: widget.windowBody), ), ), - ), - ], - ), + ], + ), + ), ), ); } diff --git a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart index 03761c94..9f303740 100644 --- a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart @@ -12,6 +12,9 @@ class PatientManagerProvider extends ChangeNotifier { bool personalMode; List? myPaitentList; Patient? selectedPatient; + String? selectedPatientProfilePictureUrl; + ImageProvider? selectedPatientProfilePicture; + bool hidePatientDetails; List? consultationNotes; List? patientDocuments; List? patientClaimsDocuments; @@ -22,6 +25,7 @@ class PatientManagerProvider extends ChangeNotifier { this.patientManagerIndex = 0, this.fileViewerIndex = 0, this.personalMode = true, + this.hidePatientDetails = true, }); void reset() { @@ -56,6 +60,17 @@ class PatientManagerProvider extends ChangeNotifier { notifyListeners(); } + void setSelectedPatientProfilePicUrl(String url) { + selectedPatientProfilePictureUrl = url; + selectedPatientProfilePicture = url.isNotEmpty ? NetworkImage(url) : null; + notifyListeners(); + } + + void setHidePatientDetails(bool hidePatientDetails) { + this.hidePatientDetails = hidePatientDetails; + notifyListeners(); + } + void setMyPatientList({required List? myPaitentList}) { this.myPaitentList = myPaitentList ?? []; notifyListeners(); diff --git a/Frontend/lib/mih_packages/mih_home/mih_home.dart b/Frontend/lib/mih_packages/mih_home/mih_home.dart index 877057e6..4e11ae75 100644 --- a/Frontend/lib/mih_packages/mih_home/mih_home.dart +++ b/Frontend/lib/mih_packages/mih_home/mih_home.dart @@ -180,7 +180,7 @@ class _MihHomeState extends State { Future getUserData() async { if (!mounted) return; String url; - await MihUserServices().getUserDetails( + await MihUserServices().getMyUserDetails( context, ); if (!mounted) return; diff --git a/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart index bcbfb931..df3bdac4 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart @@ -6,7 +6,6 @@ import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manag import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_access_controls_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_service_calls.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; @@ -47,7 +46,7 @@ class _BuildPatientsListState extends State { Future hasAccessToProfile(MzansiProfileProvider profileProvider, PatientManagerProvider patientManagerProvider, int index) async { var hasAccess = false; - await MIHApiCalls.checkBusinessAccessToPatient( + await MihAccessControlsServices.checkBusinessAccessToPatient( profileProvider.business!.business_id, patientManagerProvider.patientSearchResults[index].app_id) .then((results) { @@ -71,7 +70,7 @@ class _BuildPatientsListState extends State { Future getAccessStatusOfProfile(MzansiProfileProvider profileProvider, PatientManagerProvider patientManagerProvider, int index) async { var accessStatus = ""; - await MIHApiCalls.checkBusinessAccessToPatient( + await MihAccessControlsServices.checkBusinessAccessToPatient( profileProvider.business!.business_id, patientManagerProvider.patientSearchResults[index].app_id) .then((results) { @@ -373,7 +372,8 @@ class _BuildPatientsListState extends State { child: Center( child: MihButton( onPressed: () async { - await MIHApiCalls.reapplyPatientAccessAPICall( + await MihAccessControlsServices + .reapplyPatientAccessAPICall( profileProvider.business!.business_id, patientManagerProvider .patientSearchResults[index].app_id, 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 e5722c52..d6038ea5 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 @@ -39,6 +39,8 @@ class _PatientProfileTileState extends State { await MihPatientServices() .getPatientDetails(app_id, patientManagerProvider); } + patientManagerProvider.setSelectedPatientProfilePicUrl( + profileProvider.userProfilePicUrl!); patientManagerProvider.setPersonalMode(true); if (patientManagerProvider.selectedPatient != null) { context.goNamed( diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart index a5a04253..eaff2452 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart @@ -1,11 +1,10 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; @@ -23,121 +22,132 @@ class PatientInfo extends StatefulWidget { } class _PatientInfoState extends State { - final idController = TextEditingController(); - final fnameController = TextEditingController(); - final lnameController = TextEditingController(); - final cellController = TextEditingController(); - final emailController = TextEditingController(); - final medNoController = TextEditingController(); - final medNameController = TextEditingController(); - final medSchemeController = TextEditingController(); - final addressController = TextEditingController(); - final medAidController = TextEditingController(); - final medMainMemController = TextEditingController(); - final medAidCodeController = TextEditingController(); - final _formKey = GlobalKey(); double textFieldWidth = 300; late String medAid; late bool medAidPosition; - Widget getPatientDetailsField() { - return Center( - child: Wrap( - spacing: 10, - runSpacing: 10, + String getDisplayText( + PatientManagerProvider patientManagerProvider, String originalText) { + int textLength = originalText.length >= 13 ? 13 : originalText.length; + String displayText = ""; + if (patientManagerProvider.hidePatientDetails) { + for (int i = 0; i < textLength; i++) { + displayText += "●"; + } + } else { + displayText = originalText; + } + return displayText; + } + + Widget buildPatientInfoCard(PatientManagerProvider patientManagerProvider) { + TextStyle titleStyle = TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + TextStyle subtitleStyle = TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + TextStyle subtitleHeadingStyle = TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + return MihPackageWindow( + fullscreen: false, + windowTitle: "Patient Details Card", + onWindowTapClose: null, + backgroundColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + foregroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + windowBody: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: idController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "ID No.", - // validator: (value) { - // return MihValidationServices().isEmpty(value); - // }, + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "${patientManagerProvider.selectedPatient!.first_name} ${patientManagerProvider.selectedPatient!.last_name}", + style: titleStyle, + ), + RichText( + text: TextSpan( + children: [ + TextSpan( + text: "ID No: ", + style: subtitleHeadingStyle, + ), + TextSpan( + text: getDisplayText(patientManagerProvider, + patientManagerProvider.selectedPatient!.id_no), + style: subtitleStyle, + ), + ], + ), + ), + RichText( + text: TextSpan( + children: [ + TextSpan( + text: "Cell No: ", + style: subtitleHeadingStyle, + ), + TextSpan( + text: getDisplayText( + patientManagerProvider, + patientManagerProvider + .selectedPatient!.cell_no), + style: subtitleStyle, + ), + ], + ), + ), + ], + ), + ), + ], + ), + RichText( + text: TextSpan( + children: [ + TextSpan( + text: "Email: ", + style: subtitleHeadingStyle, + ), + TextSpan( + text: getDisplayText(patientManagerProvider, + patientManagerProvider.selectedPatient!.email), + style: subtitleStyle, + ), + ], ), ), - SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: fnameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "First Name", - ), - ), - SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: lnameController, - multiLineInput: false, - requiredText: true, - hintText: "Surname", - readOnly: true, - ), - ), - SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: cellController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Cell No.", - ), - ), - SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: emailController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Email", - ), - ), - SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - height: 100, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: addressController, - multiLineInput: true, - requiredText: true, - readOnly: true, - hintText: "Address", + RichText( + text: TextSpan( + children: [ + TextSpan( + text: "Address: ", + style: subtitleHeadingStyle, + ), + TextSpan( + text: getDisplayText(patientManagerProvider, + patientManagerProvider.selectedPatient!.address), + style: subtitleStyle, + ), + ], ), ), ], @@ -145,170 +155,111 @@ class _PatientInfoState extends State { ); } - Widget getMedAidDetailsFields() { - List medAidDet = []; - medAidDet.add( - SizedBox( - width: textFieldWidth, - child: MihToggle( - hintText: "Medical Aid", - initialPostion: medAidPosition, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - secondaryFillColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - readOnly: true, - onChange: (value) { - if (value) { - setState(() { - medAidController.text = "Yes"; - medAidPosition = value; - }); - } else { - setState(() { - medAidController.text = "No"; - medAidPosition = value; - }); - } - }, - ), - // MihTextFormField( - // // width: textFieldWidth, - // fillColor: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // inputColor: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // controller: medAidController, - // multiLineInput: false, - // requiredText: true, - // readOnly: true, - // hintText: "Medical Aid", - // ), - ), + Widget buildMedAidInfoCard(PatientManagerProvider patientManagerProvider) { + TextStyle titleStyle = TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ); - bool req; - if (medAid == "Yes") { - req = true; - } else { - req = false; - } - medAidDet.addAll([ - Visibility( - visible: req, - child: SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: medMainMemController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Main Member", + TextStyle subtitleStyle = TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + TextStyle subtitleHeadingStyle = TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + return MihPackageWindow( + fullscreen: false, + windowTitle: "Medical Aid Card", + onWindowTapClose: null, + backgroundColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + foregroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + windowBody: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "${patientManagerProvider.selectedPatient!.medical_aid_name} - ${patientManagerProvider.selectedPatient!.medical_aid_scheme}", + style: titleStyle, + ), + RichText( + text: TextSpan( + children: [ + TextSpan( + text: "Main Member: ", + style: subtitleHeadingStyle, + ), + TextSpan( + text: getDisplayText( + patientManagerProvider, + patientManagerProvider + .selectedPatient!.medical_aid_main_member), + style: subtitleStyle, + ), + ], + ), + ), + RichText( + text: TextSpan( + children: [ + TextSpan( + text: "No: ", + style: subtitleHeadingStyle, + ), + TextSpan( + text: getDisplayText( + patientManagerProvider, + patientManagerProvider + .selectedPatient!.medical_aid_no), + style: subtitleStyle, + ), + ], + ), + ), + RichText( + text: TextSpan( + children: [ + TextSpan( + text: "Code: ", + style: subtitleHeadingStyle, + ), + TextSpan( + text: getDisplayText( + patientManagerProvider, + patientManagerProvider + .selectedPatient!.medical_aid_code), + style: subtitleStyle, + ), + ], + ), + ), + ], + ), + ), + ], ), - ), - ), - Visibility( - visible: req, - child: SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: medNoController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "No.", - ), - ), - ), - Visibility( - visible: req, - child: SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: medAidCodeController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Code", - ), - ), - ), - Visibility( - visible: req, - child: SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: medNameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Name", - ), - ), - ), - Visibility( - visible: req, - child: SizedBox( - width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: medSchemeController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Plan", - ), - ), - ), - ]); - return Center( - child: Wrap( - spacing: 10, - runSpacing: 10, - children: medAidDet, + ], ), ); } void initialiseControllers(PatientManagerProvider patientManagerProvider) { - idController.text = patientManagerProvider.selectedPatient!.id_no; - fnameController.text = patientManagerProvider.selectedPatient!.first_name; - lnameController.text = patientManagerProvider.selectedPatient!.last_name; - cellController.text = patientManagerProvider.selectedPatient!.cell_no; - emailController.text = patientManagerProvider.selectedPatient!.email; - medNameController.text = - patientManagerProvider.selectedPatient!.medical_aid_name; - medNoController.text = - patientManagerProvider.selectedPatient!.medical_aid_no; - medSchemeController.text = - patientManagerProvider.selectedPatient!.medical_aid_scheme; - addressController.text = patientManagerProvider.selectedPatient!.address; - medAidController.text = patientManagerProvider.selectedPatient!.medical_aid; - medMainMemController.text = - patientManagerProvider.selectedPatient!.medical_aid_main_member; - medAidCodeController.text = - patientManagerProvider.selectedPatient!.medical_aid_code; medAid = patientManagerProvider.selectedPatient!.medical_aid; if (medAid == "Yes") { medAidPosition = true; @@ -327,18 +278,6 @@ class _PatientInfoState extends State { @override void dispose() { - idController.dispose(); - fnameController.dispose(); - lnameController.dispose(); - cellController.dispose(); - emailController.dispose(); - medNameController.dispose(); - medNoController.dispose(); - medSchemeController.dispose(); - addressController.dispose(); - medAidController.dispose(); - medMainMemController.dispose(); - medAidCodeController.dispose(); super.dispose(); } @@ -364,60 +303,50 @@ class _PatientInfoState extends State { initialiseControllers(patientManagerProvider); return Stack( children: [ - MihSingleChildScroll( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - MihForm( - formKey: _formKey, - formFields: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - //crossAxisAlignment: , - children: [ - Text( - "Personal", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - ), - ]), - Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark")), - const SizedBox(height: 10), - getPatientDetailsField(), - const SizedBox(height: 10), - Center( - child: Text( - "Medical Aid", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ), - Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark")), - const SizedBox(height: 10), - getMedAidDetailsFields(), - ], - ), - ], + Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + MihCircleAvatar( + imageFile: + patientManagerProvider.selectedPatientProfilePicture, + width: 160, + editable: false, + fileNameController: null, + userSelectedfile: null, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onChange: () {}, + ), + const SizedBox(height: 10), + buildPatientInfoCard(patientManagerProvider), + const SizedBox(height: 10), + buildMedAidInfoCard(patientManagerProvider), + ], + ), + Positioned( + right: 5, + top: 5, + child: MihButton( + width: 40, + height: 40, + onPressed: () { + patientManagerProvider.setHidePatientDetails( + !patientManagerProvider.hidePatientDetails); + }, + buttonColor: patientManagerProvider.hidePatientDetails + ? MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark") + : MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Icon( + patientManagerProvider.hidePatientDetails + ? Icons.visibility + : Icons.visibility_off, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), ), ), Visibility( @@ -450,13 +379,6 @@ class _PatientInfoState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - // context.goNamed( - // 'patientProfileEdit', - // extra: PatientEditArguments( - // profileProvider.user!, - // patientManagerProvider.selectedPatient!, - // ), - // ); showEditPatientWindow(); }, ) diff --git a/Frontend/lib/mih_services/mih_access_controls_services.dart b/Frontend/lib/mih_services/mih_access_controls_services.dart index 322031f9..69d40a66 100644 --- a/Frontend/lib/mih_services/mih_access_controls_services.dart +++ b/Frontend/lib/mih_services/mih_access_controls_services.dart @@ -35,6 +35,29 @@ class MihAccessControlsServices { } } + /// This function is used to check if a business has access to a specific patients profile. + /// + /// Patameters: String business_id & app_id (app_id of patient). + /// + /// Returns List (List of access that match the above parameters). + static Future> checkBusinessAccessToPatient( + String business_id, + String app_id, + ) async { + final response = await http.get(Uri.parse( + "${AppEnviroment.baseApiUrl}/access-requests/patient/check/$business_id?app_id=$app_id")); + // var errorCode = response.statusCode.toString(); + //print(response.body); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List patientAccesses = List.from( + l.map((model) => PatientAccess.fromJson(model))); + return patientAccesses; + } else { + throw Exception('failed to pull patient access for business'); + } + } + /// This function is used to create patient access and trigger notification to patient /// /// Patameters:- diff --git a/Frontend/lib/mih_services/mih_service_calls.dart b/Frontend/lib/mih_services/mih_service_calls.dart deleted file mode 100644 index d0de0899..00000000 --- a/Frontend/lib/mih_services/mih_service_calls.dart +++ /dev/null @@ -1,569 +0,0 @@ -import 'dart:convert'; -import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_my_business_user_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_notification_services.dart'; -import 'package:flutter/material.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; -import 'package:supertokens_flutter/supertokens.dart'; -import 'package:supertokens_flutter/http.dart' as http; -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'; -import '../mih_components/mih_objects/app_user.dart'; -import '../mih_components/mih_objects/arguments.dart'; -import '../mih_components/mih_objects/business.dart'; -import '../mih_components/mih_objects/business_user.dart'; -import '../mih_components/mih_objects/notification.dart'; -import '../mih_components/mih_objects/patient_access.dart'; -import '../mih_components/mih_objects/patient_queue.dart'; -import '../mih_components/mih_objects/patients.dart'; - -class MIHApiCalls { - final baseAPI = AppEnviroment.baseApiUrl; - -//================== PROFILE DATA ========================================================================== - - /// This function is used to get profile details of signed in user. - /// - /// Patameters: int notificationAmount which is used to get number of notifications to show. - /// - /// Returns HomeArguments which contains:- - /// - Signed In user data. - /// - Business user belongs to. - /// - Business User details. - /// - notifications. - /// - user profile picture. - Future getProfile( - int notificationAmount, - BuildContext context, - ) async { - AppUser userData; - Business? busData; - BusinessUser? bUserData; - Patient? patientData; - List notifi; - String userPic; - - // Get Userdata - var uid = await SuperTokens.getUserId(); - AppUser? user = await MihUserServices().getUserDetails(context); - if (user != null) { - userData = user; - } else { - throw Exception("Error: GetUserData returned null"); - } - - // Get BusinessUserdata - BusinessUser? businessUser = - await MihMyBusinessUserServices().getBusinessUser(context); - if (businessUser != null) { - bUserData = businessUser; - } else { - bUserData = null; - } - - // Get Businessdata - Business? business = - await MihBusinessDetailsServices().getBusinessDetailsByUser(context); - if (business != null) { - busData = business; - } else { - busData = null; - } - - //get profile picture - if (userData.pro_pic_path == "") { - userPic = ""; - } else { - userPic = - await MihFileApi.getMinioFileUrl(userData.pro_pic_path, context); - } - - //Get Notifications - notifi = await MihNotificationApis().getNotificationByUser( - uid, - notificationAmount, - ); - - //get patient profile - // Patient? patient = await MihPatientServices().getPatientDetails( - // uid, - // ); - // if (patient != null) { - // patientData = patient; - // } else { - // patientData = null; - // } - - return HomeArguments( - userData, bUserData, busData, patientData, notifi, userPic); - } - -//================== BUSINESS PATIENT/PERSONAL ACCESS ========================================================================== - - /// This function is used to check if a business has access to a specific patients profile. - /// - /// Patameters: String business_id & app_id (app_id of patient). - /// - /// Returns List (List of access that match the above parameters). - static Future> checkBusinessAccessToPatient( - String business_id, - String app_id, - ) async { - final response = await http.get(Uri.parse( - "${AppEnviroment.baseApiUrl}/access-requests/patient/check/$business_id?app_id=$app_id")); - // var errorCode = response.statusCode.toString(); - //print(response.body); - - if (response.statusCode == 200) { - Iterable l = jsonDecode(response.body); - List patientAccesses = List.from( - l.map((model) => PatientAccess.fromJson(model))); - return patientAccesses; - } else { - throw Exception('failed to pull patient access for business'); - } - } - - /// This function is used to UPDATE access the business has. - /// - /// Patameters:- - /// String business_id, - /// String business_name, - /// String app_id, - /// String status, - /// String approved_by, - /// AppUser signedInUser, - /// BuildContext context, - /// - /// Returns void (on success 200 navigate to /mih-access ). - static Future updatePatientAccessAPICall( - String business_id, - String business_name, - String app_id, - String status, - String approved_by, - AppUser signedInUser, - BuildContext context, - ) async { - var response = await http.put( - Uri.parse( - "${AppEnviroment.baseApiUrl}/access-requests/update/permission/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - // business_id: str - // app_id: str - // status: str - // approved_by: str - body: jsonEncode({ - "business_id": business_id, - "app_id": app_id, - "status": status, - "approved_by": approved_by, - }), - ); - if (response.statusCode == 200) { - //Navigator.of(context).pushNamed('/home'); - Navigator.of(context).pop(); - Navigator.of(context).pop(); - Navigator.of(context).pushNamed( - '/mih-access', - arguments: signedInUser, - ); - String message = ""; - if (status == "approved") { - message = - "You've successfully approved the access request! $business_name now has access to your profile forever."; - } else { - message = - "You've declined the access request. $business_name will not have access to your profile."; - } - successPopUp(message, context); - } else { - internetConnectionPopUp(context); - } - } - - /// This function is used to reapply for access to patient. - /// - /// Patameters:- - /// String business_id, - /// String app_id, - /// BuildContext context, - /// - /// Returns void (on success 200 navigate to /mih-access ). - static Future reapplyPatientAccessAPICall( - String business_id, - String app_id, - bool personalSelected, - BusinessArguments args, - BuildContext context, - ) async { - var response = await http.put( - Uri.parse("${AppEnviroment.baseApiUrl}/access-requests/re-apply/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - // business_id: str - // app_id: str - // status: str - // approved_by: str - body: jsonEncode({ - "business_id": business_id, - "app_id": app_id, - }), - ); - if (response.statusCode == 200) { - MihNotificationApis.reapplyAccessRequestNotificationAPICall( - app_id, personalSelected, args, context); - //notification here - } else { - internetConnectionPopUp(context); - } - } - - /// This function is used to create patient access and trigger notification to patient - /// - /// Patameters:- - /// String business_id, - /// String app_id, - /// String type, - /// String requested_by, - /// BuildContext context, - /// - /// Returns void (triggers notification of success 201). - static Future addPatientAccessAPICall( - String business_id, - String app_id, - String type, - String requested_by, - bool personalSelected, - BusinessArguments args, - BuildContext context, - ) async { - var response = await http.post( - Uri.parse("${AppEnviroment.baseApiUrl}/access-requests/insert/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - // business_id: str - // app_id: str - // type: str - // requested_by: str - body: jsonEncode({ - "business_id": business_id, - "app_id": app_id, - "type": type, - "requested_by": requested_by, - }), - ); - if (response.statusCode == 201) { - MihNotificationApis.addAccessRequestNotificationAPICall( - app_id, requested_by, personalSelected, args, context); - } else { - internetConnectionPopUp(context); - } - } - - //================== PATIENT DATA ========================================================================== - - /// This function is used to fetch a list of patients matching a search criteria - /// - /// Patameters: String dsearch. - /// - /// Returns List. - - static Future> fetchPatients(String search) async { - final response = await http - .get(Uri.parse("${AppEnviroment.baseApiUrl}/patients/search/$search")); - if (response.statusCode == 200) { - Iterable l = jsonDecode(response.body); - List patients = - List.from(l.map((model) => Patient.fromJson(model))); - return patients; - } else { - throw Exception('failed to load patients'); - } - } - - /// This function is used to fetch a patient matching a app_id - /// - /// Patameters: String app_id. - /// - /// Returns Patient. - static Future fetchPatientByAppId( - String app_id, - ) async { - final response = await http - .get(Uri.parse("${AppEnviroment.baseApiUrl}/patients/$app_id")); - // errorCode = response.statusCode.toString(); - // errorBody = response.body; - //print(response.body); - if (response.statusCode == 200) { - Patient patient = Patient.fromJson(jsonDecode(response.body)); - // userData = u; - // Iterable l = jsonDecode(response.body); - // List patients = - // List.from(l.map((model) => Patient.fromJson(model))); - return patient; - } else { - throw Exception('failed to load patient'); - } - } - - //================== APPOINTMENT/ PATIENT QUEUE ========================================================================== - - /// This function is used to fetch a list of appointments for a doctors office for a date. - /// - /// Patameters: String date & business_id . - /// - /// Returns List. - static Future> fetchBusinessAppointmentsAPICall( - String date, - String business_id, - ) async { - //print("Patien manager page: $endpoint"); - final response = await http.get(Uri.parse( - "${AppEnviroment.baseApiUrl}/queue/appointments/business/$business_id?date=$date")); - // print("Here"); - // print("Body: ${response.body}"); - // print("Code: ${response.statusCode}"); - // errorCode = response.statusCode.toString(); - // errorBody = response.body; - - if (response.statusCode == 200) { - //print("Here1"); - Iterable l = jsonDecode(response.body); - //print("Here2"); - List patientQueue = List.from( - l.map((model) => PatientQueue.fromJson(model))); - //print("Here3"); - //print(patientQueue); - return patientQueue; - } else { - throw Exception('failed to fatch patient queue'); - } - } - - /// This function is used to fetch a list of appointments for a doctors office for a date. - /// - /// Patameters: String date & business_id . - /// - /// Returns List. - static Future> fetchPersonalAppointmentsAPICall( - String date, - String app_id, - ) async { - //print("Patien manager page: $endpoint"); - final response = await http.get(Uri.parse( - "${AppEnviroment.baseApiUrl}/queue/appointments/personal/$app_id?date=$date")); - // print("Here"); - // print("Body: ${response.body}"); - // print("Code: ${response.statusCode}"); - // errorCode = response.statusCode.toString(); - // errorBody = response.body; - - if (response.statusCode == 200) { - //print("Here1"); - Iterable l = jsonDecode(response.body); - //print("Here2"); - List patientQueue = List.from( - l.map((model) => PatientQueue.fromJson(model))); - //print("Here3"); - //print(patientQueue); - return patientQueue; - } else { - throw Exception('failed to fatch patient queue'); - } - } - - /// This function is used to UPDATE AN appointments for a doctors office for a date. - /// - /// Patameters:- - /// int idpatient_queue, - /// String app_id, - /// String business_name, - /// String origDate_time, - /// String date, - /// String time, - /// BusinessArguments args, - /// BuildContext context, - /// - /// Returns VOID (TRIGGERS NOTIGICATIOPN ON SUCCESS) - static Future updateApointmentAPICall( - int idpatient_queue, - String app_id, - bool personalSelected, - String business_name, - String origDate_time, - String date, - String time, - BusinessArguments args, - BuildContext context, - ) async { - var response = await http.put( - Uri.parse("${AppEnviroment.baseApiUrl}/queue/appointment/update/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "idpatient_queue": idpatient_queue, - "date": date, - "time": time, - }), - ); - if (response.statusCode == 200) { - MihNotificationApis.addRescheduledAppointmentNotificationAPICall( - app_id, - personalSelected, - business_name, - origDate_time, - date, - time, - args, - context, - ); - } else { - internetConnectionPopUp(context); - } - } - - /// This function is used to Delete/ cancel AN appointments for a doctors office for a date. - /// - /// Patameters:- - /// int idpatient_queue, - /// PatientViewArguments args, - /// BuildContext context, - /// - /// Returns VOID (TRIGGERS NOTIGICATIOPN ON SUCCESS) - static Future deleteApointmentAPICall( - int idpatient_queue, - String app_id, - bool personalSelected, - String date_time, - BusinessArguments args, - BuildContext context, - ) async { - var response = await http.delete( - Uri.parse("${AppEnviroment.baseApiUrl}/queue/appointment/delete/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({"idpatient_queue": idpatient_queue}), - ); - //print("Here4"); - //print(response.statusCode); - if (response.statusCode == 200) { - MihNotificationApis.addCancelledAppointmentNotificationAPICall( - app_id, - personalSelected, - date_time, - args, - context, - ); - // Navigator.of(context).pop(); - // Navigator.of(context).pop(); - // String message = - // "The note has been deleted successfully. This means it will no longer be visible on your and cannot be used for future appointments."; - // successPopUp(message, context); - } else { - internetConnectionPopUp(context); - } - } - - /// This function is used to create AN appointments for a doctors office for a date. - /// - /// Patameters:- - /// int idpatient_queue, - /// PatientViewArguments args, - /// BuildContext context, - /// - /// Returns VOID (TRIGGERS NOTIGICATIOPN ON SUCCESS) - static Future addAppointmentAPICall( - String business_id, - String app_id, - bool personalSelected, - String date, - String time, - BusinessArguments args, - BuildContext context, - ) async { - var response = await http.post( - Uri.parse("${AppEnviroment.baseApiUrl}/queue/appointment/insert/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "business_id": business_id, - "app_id": app_id, - "date": date, - "time": time, - }), - ); - if (response.statusCode == 201) { - // Navigator.pushNamed(context, '/patient-manager/patient', - // arguments: widget.signedInUser); - // String message = - // "The appointment has been successfully booked!\n\nAn approval request as been sent to the patient.Once the access request has been approved, you will be able to access the patientAccesses profile. ou can check the status of your request in patient queue under the appointment."; - // "${fnameController.text} ${lnameController.text} patient profiole has been successfully added!\n"; - // Navigator.pop(context); - // Navigator.pop(context); - // Navigator.pop(context); - // setState(() { - // dateController.text = ""; - // timeController.text = ""; - // }); - // Navigator.of(context).pushNamed( - // '/patient-manager', - // arguments: BusinessArguments( - // widget.arguments.signedInUser, - // widget.arguments.businessUser, - // widget.arguments.business, - // ), - // ); - // successPopUp(message); - // String app_id, - // String date, - // String time, - // BusinessArguments args, - // BuildContext context, - MihNotificationApis.addNewAppointmentNotificationAPICall( - app_id, - personalSelected, - date, - time, - args, - context, - ); - } else { - internetConnectionPopUp(context); - } - } - - //================== POP UPS ========================================================================== - - static void internetConnectionPopUp(BuildContext context) { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage( - errorType: "Internet Connection", - ); - }, - ); - } - - static void successPopUp(String message, BuildContext context) { - showDialog( - context: context, - builder: (context) { - return MIHSuccessMessage( - successType: "Success", - successMessage: message, - ); - }, - ); - } -} diff --git a/Frontend/lib/mih_services/mih_user_services.dart b/Frontend/lib/mih_services/mih_user_services.dart index 0d8dadbb..e2e58e6a 100644 --- a/Frontend/lib/mih_services/mih_user_services.dart +++ b/Frontend/lib/mih_services/mih_user_services.dart @@ -99,7 +99,26 @@ class MihUserServices { } } - Future getUserDetails( + Future getMIHUserDetails( + String app_id, + BuildContext context, + ) async { + var response = await http.get( + Uri.parse("${AppEnviroment.baseApiUrl}/user/$app_id"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + ); + if (response.statusCode == 200) { + String body = response.body; + var jsonBody = jsonDecode(body); + return AppUser.fromJson(jsonBody); + } else { + return null; + } + } + + Future getMyUserDetails( BuildContext context, ) async { String app_id = await SuperTokens.getUserId(); @@ -109,7 +128,6 @@ class MihUserServices { "Content-Type": "application/json; charset=UTF-8" }, ); - if (response.statusCode == 200) { String body = response.body; var jsonBody = jsonDecode(body); From c5713cf6e0a7721bbd1ea9636cf9ac867be53e54 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 13 Nov 2025 14:33:31 +0200 Subject: [PATCH 03/56] QOL: Patient Manager overhaul pt2 --- .../build_claim_statement_files_list.dart | 6 +++ .../list_builders/build_files_list.dart | 48 +++++++++++++++++++ .../list_builders/build_notes_list.dart | 6 +++ 3 files changed, 60 insertions(+) diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart index 30bec822..b34611ed 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart @@ -331,6 +331,12 @@ class _BuildClaimStatementFileListState itemCount: patientManagerProvider.patientClaimsDocuments!.length, itemBuilder: (context, index) { return ListTile( + leading: Icon( + Icons.picture_as_pdf, + size: 50, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), title: Text( patientManagerProvider .patientClaimsDocuments![index].file_name, diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart index a7b38555..b6050814 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart @@ -2,7 +2,9 @@ import 'dart:async'; import 'package:fl_downloader/fl_downloader.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; @@ -324,6 +326,46 @@ class _BuildFilesListState extends State { ); } + Widget getFileIcon(String extension) { + switch (extension) { + case ("pdf"): + return Icon( + Icons.picture_as_pdf, + size: 50, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + case ("jpg"): + return Icon( + FontAwesomeIcons.image, + size: 50, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + case ("png"): + return Icon( + FontAwesomeIcons.image, + size: 50, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + case ("gif"): + return Icon( + FontAwesomeIcons.image, + size: 50, + color: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + default: + return Icon( + Icons.image_not_supported, + size: 50, + color: MihColors.getSilverColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + } + } + @override void dispose() { // TODO: implement dispose @@ -367,7 +409,13 @@ class _BuildFilesListState extends State { }, itemCount: patientManagerProvider.patientDocuments!.length, itemBuilder: (context, index) { + String fileExtension = patientManagerProvider + .patientDocuments![index].file_name + .split(".")[1] + .toLowerCase(); + KenLogger.success(fileExtension); return ListTile( + leading: getFileIcon(fileExtension), title: Text( patientManagerProvider.patientDocuments![index].file_name, style: TextStyle( diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart index 832d0d9f..993c12b1 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart @@ -282,6 +282,12 @@ class _BuildNotesListState extends State { notePreview = "${notePreview.substring(0, 30)} ..."; } return ListTile( + leading: Icon( + Icons.note, + size: 50, + color: MihColors.getGoldColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), title: Text( "${patientManagerProvider.consultationNotes![index].note_name}\n${patientManagerProvider.consultationNotes![index].doc_office} - ${patientManagerProvider.consultationNotes![index].doctor}", style: TextStyle( From 5770f6c35334c99d79c7395ec784743cdac95a34 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 13 Nov 2025 14:52:26 +0200 Subject: [PATCH 04/56] QOL: Patient Manager overhaul pt3 --- .../build_my_patient_list_list.dart | 16 ++++++++++++++++ .../pat_profile/package_tools/patient_info.dart | 6 ++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart index c588abf5..1c6406c0 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart @@ -5,8 +5,10 @@ import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profil import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_calendar_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_date_field.dart'; @@ -524,6 +526,15 @@ class _BuildPatientsListState extends State { patientManagerProvider.myPaitentList![index].app_id, patientManagerProvider) .then((result) {}); + await MihUserServices() + .getMIHUserDetails( + patientManagerProvider.myPaitentList![index].app_id, context) + .then((user) async { + user; + String url = + await MihFileApi.getMinioFileUrl(user!.pro_pic_path, context); + patientManagerProvider.setSelectedPatientProfilePicUrl(url); + }); patientProfileChoicePopUp( profileProvider, patientManagerProvider, index, width); } else { @@ -538,6 +549,11 @@ class _BuildPatientsListState extends State { ); } + @override + void initState() { + super.initState(); + } + @override void dispose() { dateController.dispose(); diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart index eaff2452..bf34933e 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart @@ -195,7 +195,7 @@ class _PatientInfoState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "${patientManagerProvider.selectedPatient!.medical_aid_name} - ${patientManagerProvider.selectedPatient!.medical_aid_scheme}", + "${patientManagerProvider.selectedPatient!.medical_aid} - ${patientManagerProvider.selectedPatient!.medical_aid_scheme}", style: titleStyle, ), RichText( @@ -322,7 +322,9 @@ class _PatientInfoState extends State { const SizedBox(height: 10), buildPatientInfoCard(patientManagerProvider), const SizedBox(height: 10), - buildMedAidInfoCard(patientManagerProvider), + if (patientManagerProvider.selectedPatient!.medical_aid == + "Yes") + buildMedAidInfoCard(patientManagerProvider), ], ), Positioned( From 66db154b020b9cc083d31e372a2c5810e1dc5a9e Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 14 Nov 2025 11:23:31 +0200 Subject: [PATCH 05/56] user service update --- Frontend/lib/mih_packages/mih_home/mih_home.dart | 8 +++----- Frontend/lib/mih_services/mih_user_services.dart | 8 ++++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Frontend/lib/mih_packages/mih_home/mih_home.dart b/Frontend/lib/mih_packages/mih_home/mih_home.dart index 4e11ae75..7a223326 100644 --- a/Frontend/lib/mih_packages/mih_home/mih_home.dart +++ b/Frontend/lib/mih_packages/mih_home/mih_home.dart @@ -53,7 +53,7 @@ class _MihHomeState extends State { context.read(); // Note: getUserData sets user and userProfilePicUrl in the provider if (mzansiProfileProvider.user == null) { - await getUserData(); + await getUserData(mzansiProfileProvider); } // Note: getUserConsentStatus sets userConsent in the provider if (mzansiProfileProvider.userConsent == null) { @@ -177,12 +177,10 @@ class _MihHomeState extends State { }); } - Future getUserData() async { + Future getUserData(MzansiProfileProvider profileProvider) async { if (!mounted) return; String url; - await MihUserServices().getMyUserDetails( - context, - ); + await MihUserServices().getMyUserDetails(profileProvider); if (!mounted) return; url = await MihFileApi.getMinioFileUrl( context.read().user!.pro_pic_path, diff --git a/Frontend/lib/mih_services/mih_user_services.dart b/Frontend/lib/mih_services/mih_user_services.dart index e2e58e6a..b7785b17 100644 --- a/Frontend/lib/mih_services/mih_user_services.dart +++ b/Frontend/lib/mih_services/mih_user_services.dart @@ -119,7 +119,7 @@ class MihUserServices { } Future getMyUserDetails( - BuildContext context, + MzansiProfileProvider profileProvider, ) async { String app_id = await SuperTokens.getUserId(); var response = await http.get( @@ -131,9 +131,9 @@ class MihUserServices { if (response.statusCode == 200) { String body = response.body; var jsonBody = jsonDecode(body); - context.read().setUser( - newUser: AppUser.fromJson(jsonBody), - ); + profileProvider.setUser( + newUser: AppUser.fromJson(jsonBody), + ); return AppUser.fromJson(jsonBody); } else { return null; From 5903fcd31a6be4b8ee3e7593aaf3efaeee5ff0a7 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 14 Nov 2025 11:28:17 +0200 Subject: [PATCH 06/56] reduce load speed --- Frontend/web/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/web/index.html b/Frontend/web/index.html index 3bb4dfc8..1b438bb8 100644 --- a/Frontend/web/index.html +++ b/Frontend/web/index.html @@ -438,7 +438,7 @@ ); loadMainDartJs(); } - }, 4000); + }, 500); var finishLoad = new Date(); var loadTime = (finishLoad.getTime() - startLoad.getTime()); console.log("Load Time: " + loadTime); From 652d4bb2fd5c4086bb2414837b979024136447c2 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 14 Nov 2025 12:07:36 +0200 Subject: [PATCH 07/56] increase load --- Frontend/web/index.html | 197 ++++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 98 deletions(-) diff --git a/Frontend/web/index.html b/Frontend/web/index.html index 1b438bb8..27d81740 100644 --- a/Frontend/web/index.html +++ b/Frontend/web/index.html @@ -362,112 +362,113 @@ }); +  From 0a03b1c60c78dcd73ee0fa7cb5281ea8fc7d5bbd Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 14 Nov 2025 12:22:21 +0200 Subject: [PATCH 08/56] web loadtime --- Frontend/web/index.html | 51 ++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/Frontend/web/index.html b/Frontend/web/index.html index 27d81740..3dfe24f1 100644 --- a/Frontend/web/index.html +++ b/Frontend/web/index.html @@ -365,7 +365,7 @@     var serviceWorkerVersion = '{{flutter_service_worker_version}}';     var scriptLoaded = false; -    function loadMainDartJs() { +    function loadMainDartJs(isUpdate) {       console.log('Loading app...');       if (scriptLoaded) {         return; @@ -380,6 +380,17 @@         onEntrypointLoaded: function (engineInitializer) {           engineInitializer.initializeEngine().then(function (appRunner) {             appRunner.runApp(); +            + // --- NEW PROMPT LOCATION --- + if (isUpdate) { + // Only show prompt AFTER the old app (the one currently running) has loaded + console.log('New app version installed. Prompting for reload.'); + if (confirm('A new version of the app is available. Refresh now to update?')) { + window.location.reload(); + } + } + // --------------------------- +           });         }       }); @@ -389,7 +400,7 @@     function getCleanVersion(version) {       return version.replace(/"/g, '');     } - +         if ('serviceWorker' in navigator) {       var startLoad = new Date();       // Service workers are supported. Use them. @@ -399,22 +410,16 @@         navigator.serviceWorker.register(serviceWorkerUrl)           .then((reg) => { + + // Flag to track if this registration resulted in an update + let isUpdateInstallation = false; +             function waitForActivation(serviceWorker) {               serviceWorker.addEventListener('statechange', () => {                 if (serviceWorker.state == 'activated') {                   console.log('Installed new service worker.'); -                  loadMainDartJs(); -                  // Optional: Prompt user to reload for the new version to take effect -                  // The user is currently running the OLD cached version of the app. -                  // This prompt is generally preferred over the previous logic. -                  if (navigator.serviceWorker.controller) { -                    // Only prompt if this isn't the first time loading. -                    console.log('New app version activated. Prompting for reload.'); -                    // You can replace this confirm with a better UI notification. -                    if (confirm('A new version of the app is available. Refresh now to update?')) { -                      window.location.reload(); -                    } -                  } +                  // Pass the update flag to loadMainDartJs +                  loadMainDartJs(isUpdateInstallation);                 }               });             } @@ -425,26 +430,27 @@             console.log('Active Service Worker Version: ' + (currentSWVersion || 'None'));             const isMatch = currentSWVersion === cleanServiceWorkerVersion;             console.log('Latest Service Worker Installed: ' + isMatch); - +                         if (!reg.active && (reg.installing || reg.waiting)) {               // First time load: wait for activation.               console.log('No Service Worker Available - Installing New Service Worker.');               waitForActivation(reg.installing || reg.waiting);             } else if (!isMatch) {               // New version available: force update. + isUpdateInstallation = true; // Set flag when update is initiated               console.log('New service worker available. Updating and waiting for activation.');               reg.update();               waitForActivation(reg.installing);             } else {               // Existing service worker is still good.               console.log('Service Worker up-to-date, Loading app.'); -              loadMainDartJs(); +              loadMainDartJs(false); // No update, pass false             }           }) - .catch((error) => { - console.error('Service Worker registration failed:', error); - loadMainDartJs(); // Fallback if registration fails completely - }); +          .catch((error) => { +              console.error('Service Worker registration failed:', error); +              loadMainDartJs(false); // Fallback if registration fails completely +          });         // If service worker doesn't succeed in a reasonable amount of time, @@ -454,7 +460,7 @@             console.warn(               'Failed to load app from a service worker. Falling back to plain - From 329e450f5b9a989ee5044f13375de09a97fd992b Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 14 Nov 2025 12:33:35 +0200 Subject: [PATCH 09/56] revert --- Frontend/web/index.html | 51 +++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/Frontend/web/index.html b/Frontend/web/index.html index 3dfe24f1..27d81740 100644 --- a/Frontend/web/index.html +++ b/Frontend/web/index.html @@ -365,7 +365,7 @@     var serviceWorkerVersion = '{{flutter_service_worker_version}}';     var scriptLoaded = false; -    function loadMainDartJs(isUpdate) { +    function loadMainDartJs() {       console.log('Loading app...');       if (scriptLoaded) {         return; @@ -380,17 +380,6 @@         onEntrypointLoaded: function (engineInitializer) {           engineInitializer.initializeEngine().then(function (appRunner) {             appRunner.runApp(); -            - // --- NEW PROMPT LOCATION --- - if (isUpdate) { - // Only show prompt AFTER the old app (the one currently running) has loaded - console.log('New app version installed. Prompting for reload.'); - if (confirm('A new version of the app is available. Refresh now to update?')) { - window.location.reload(); - } - } - // --------------------------- -           });         }       }); @@ -400,7 +389,7 @@     function getCleanVersion(version) {       return version.replace(/"/g, '');     } -     +     if ('serviceWorker' in navigator) {       var startLoad = new Date();       // Service workers are supported. Use them. @@ -410,16 +399,22 @@         navigator.serviceWorker.register(serviceWorkerUrl)           .then((reg) => { - - // Flag to track if this registration resulted in an update - let isUpdateInstallation = false; -             function waitForActivation(serviceWorker) {               serviceWorker.addEventListener('statechange', () => {                 if (serviceWorker.state == 'activated') {                   console.log('Installed new service worker.'); -                  // Pass the update flag to loadMainDartJs -                  loadMainDartJs(isUpdateInstallation); +                  loadMainDartJs(); +                  // Optional: Prompt user to reload for the new version to take effect +                  // The user is currently running the OLD cached version of the app. +                  // This prompt is generally preferred over the previous logic. +                  if (navigator.serviceWorker.controller) { +                    // Only prompt if this isn't the first time loading. +                    console.log('New app version activated. Prompting for reload.'); +                    // You can replace this confirm with a better UI notification. +                    if (confirm('A new version of the app is available. Refresh now to update?')) { +                      window.location.reload(); +                    } +                  }                 }               });             } @@ -430,27 +425,26 @@             console.log('Active Service Worker Version: ' + (currentSWVersion || 'None'));             const isMatch = currentSWVersion === cleanServiceWorkerVersion;             console.log('Latest Service Worker Installed: ' + isMatch); -             +             if (!reg.active && (reg.installing || reg.waiting)) {               // First time load: wait for activation.               console.log('No Service Worker Available - Installing New Service Worker.');               waitForActivation(reg.installing || reg.waiting);             } else if (!isMatch) {               // New version available: force update. - isUpdateInstallation = true; // Set flag when update is initiated               console.log('New service worker available. Updating and waiting for activation.');               reg.update();               waitForActivation(reg.installing);             } else {               // Existing service worker is still good.               console.log('Service Worker up-to-date, Loading app.'); -              loadMainDartJs(false); // No update, pass false +              loadMainDartJs();             }           }) -          .catch((error) => { -              console.error('Service Worker registration failed:', error); -              loadMainDartJs(false); // Fallback if registration fails completely -          }); + .catch((error) => { + console.error('Service Worker registration failed:', error); + loadMainDartJs(); // Fallback if registration fails completely + });         // If service worker doesn't succeed in a reasonable amount of time, @@ -460,7 +454,7 @@             console.warn(               'Failed to load app from a service worker. Falling back to plain + From cc3d1ae430e43f3b2ee4c7e4853c64a1e3b67c49 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 14 Nov 2025 12:47:15 +0200 Subject: [PATCH 10/56] web load v2 --- Frontend/web/index.html | 187 ++++++++++++++++++++-------------------- 1 file changed, 93 insertions(+), 94 deletions(-) diff --git a/Frontend/web/index.html b/Frontend/web/index.html index 27d81740..704d4df0 100644 --- a/Frontend/web/index.html +++ b/Frontend/web/index.html @@ -363,111 +363,110 @@ From a26b826729432d8082c84ecdd8ba04b5cdd6a229 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 14 Nov 2025 12:52:11 +0200 Subject: [PATCH 11/56] increase timeut time --- Frontend/web/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/web/index.html b/Frontend/web/index.html index 704d4df0..228440e0 100644 --- a/Frontend/web/index.html +++ b/Frontend/web/index.html @@ -456,7 +456,7 @@ ); loadMainDartJs(); } - }, 500); + }, 3000); var finishLoad = new Date(); var loadTime = (finishLoad.getTime() - startLoad.getTime()); console.log("Load Time: " + loadTime); From b79decf04f495e9c056064a9784b1aa92ba16b75 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 14 Nov 2025 13:04:04 +0200 Subject: [PATCH 12/56] cancel timeout on load --- Frontend/web/index.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Frontend/web/index.html b/Frontend/web/index.html index 228440e0..7376fc04 100644 --- a/Frontend/web/index.html +++ b/Frontend/web/index.html @@ -371,6 +371,11 @@ return; } scriptLoaded = true; + // Cancel Timeut + if (window.swFallbackTimeout) { + clearTimeout(window.swFallbackTimeout); + console.log('Service worker loaded successfully - fallback timeout cancelled.'); + } {{flutter_js}} {{flutter_build_config}} _flutter.loader.load({ @@ -456,7 +461,7 @@ ); loadMainDartJs(); } - }, 3000); + }, 4000); var finishLoad = new Date(); var loadTime = (finishLoad.getTime() - startLoad.getTime()); console.log("Load Time: " + loadTime); From 121cde211fec060c27f754924487e043cd20d5b2 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 14 Nov 2025 13:53:20 +0200 Subject: [PATCH 13/56] optimisation web pt 2 --- Frontend/web/index.html | 160 ++++------------------------------------ 1 file changed, 14 insertions(+), 146 deletions(-) diff --git a/Frontend/web/index.html b/Frontend/web/index.html index 7376fc04..006730a2 100644 --- a/Frontend/web/index.html +++ b/Frontend/web/index.html @@ -21,9 +21,10 @@ - + + - + @@ -104,61 +105,6 @@ } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -