From 4fe544b35fe7ef75b1f892d9513be2031304ef20 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 13 Nov 2025 14:03:16 +0200 Subject: [PATCH] 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);