From 23cbc18649d078ffdf52d2b15223d8667099c6ea Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 12:24:40 +0200 Subject: [PATCH 01/41] add number validation --- .../lib/mih_apis/mih_validation_services.dart | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Frontend/lib/mih_apis/mih_validation_services.dart b/Frontend/lib/mih_apis/mih_validation_services.dart index 47601075..36595cee 100644 --- a/Frontend/lib/mih_apis/mih_validation_services.dart +++ b/Frontend/lib/mih_apis/mih_validation_services.dart @@ -54,6 +54,27 @@ class MihValidationServices { return "Let's create a great username for you!$errorMessage"; } + String? validateNumber(String? number, int? minValue, int? maxValue) { + String? errorMessage = ""; + if (number == null || number.isEmpty) { + errorMessage += "This field is required"; + return errorMessage; + } + int? value = int.tryParse(number); + if (value == null) { + errorMessage += "Please enter a valid number"; + return errorMessage; + } + if (value < (minValue ?? 0)) { + errorMessage += "Value must be >= ${minValue ?? 0}"; + } + if (maxValue != null && value > maxValue) { + if (errorMessage.isNotEmpty) errorMessage += "\n"; + errorMessage += "Value must be <= $maxValue"; + } + return errorMessage.isEmpty ? null : errorMessage; + } + String? validatePassword(String? password) { String? errorMessage = ""; if (password == null || password.isEmpty) { From c30b38ee3754a5f3c6881e548ef9e40fb0e0cdbe Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 12:25:52 +0200 Subject: [PATCH 02/41] create numeric stepper field --- .../mih_numeric_stepper.dart | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart diff --git a/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart new file mode 100644 index 00000000..c3e72ad6 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart @@ -0,0 +1,191 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; + +class MihNumericStepper extends StatefulWidget { + final TextEditingController controller; + final Color fillColor; + final Color inputColor; + final String hintText; + final bool requiredText; + final double? width; + final int? minValue; + final int? maxValue; + final bool validationOn; + const MihNumericStepper({ + super.key, + required this.controller, + required this.fillColor, + required this.inputColor, + required this.hintText, + required this.requiredText, + this.width, + this.minValue, + this.maxValue, + required this.validationOn, + }); + + @override + State createState() => _MihNumericStepperState(); +} + +class _MihNumericStepperState extends State { + late int _currentValue; + late bool error; + + @override + void initState() { + super.initState(); + setState(() { + _currentValue = + int.tryParse(widget.controller.text) ?? widget.minValue ?? 0; + widget.controller.text = _currentValue.toString(); + }); + print("Current Value: $_currentValue"); + } + + @override + Widget build(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Column( + 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), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.only( + top: 2.0, + left: 5.0, + ), + child: SizedBox( + width: 40, + child: IconButton.filled( + style: ButtonStyle( + backgroundColor: + WidgetStateProperty.all(widget.fillColor), + ), + color: widget.inputColor, + iconSize: 20, + onPressed: () { + print("Current Value: $_currentValue"); + if (_currentValue >= (widget.minValue ?? 0)) { + setState(() { + widget.controller.text = + (_currentValue - 1).toString(); + _currentValue = int.tryParse(widget.controller.text)!; + }); + } + print("New Current Value: $_currentValue"); + }, + icon: const Icon( + Icons.remove, + ), + ), + ), + ), + ), + Visibility( + visible: _currentValue < (widget.minValue ?? 0), + child: const SizedBox( + height: 21, + ), + ), + ], + ), + const SizedBox(width: 5), + Expanded( + child: MihTextFormField( + width: widget.width, + fillColor: widget.fillColor, + inputColor: widget.inputColor, + controller: widget.controller, + hintText: widget.hintText, + requiredText: widget.requiredText, + readOnly: true, + numberMode: true, + validator: (value) { + if (widget.validationOn) { + return MihValidationServices() + .validateNumber(value, widget.minValue, widget.maxValue); + } + return null; + }, + ), + ), + Column( + 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), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.only( + top: 2.0, + left: 5.0, + ), + child: SizedBox( + width: 40, + child: IconButton.filled( + style: ButtonStyle( + backgroundColor: + WidgetStateProperty.all(widget.fillColor), + ), + color: widget.inputColor, + iconSize: 20, + onPressed: () { + print("Current Value: $_currentValue"); + if (widget.maxValue == null || + _currentValue <= widget.maxValue!) { + setState(() { + widget.controller.text = + (_currentValue + 1).toString(); + _currentValue = int.tryParse(widget.controller.text)!; + }); + } + print("New Current Value: $_currentValue"); + }, + icon: const Icon( + Icons.add, + ), + ), + ), + ), + ), + Visibility( + visible: _currentValue < (widget.minValue ?? 0), + child: const SizedBox( + height: 20, + ), + ), + ], + ), + ], + ); + } +} From 503580066d7cc4846f7a46c746aa5355739169ef Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 12:26:03 +0200 Subject: [PATCH 03/41] add tyo test package --- .../Example/package_tools/package_tool_one.dart | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 8716ffb2..6d917af4 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 @@ -7,6 +7,7 @@ import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_numeric_stepper.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; @@ -35,6 +36,7 @@ class _PackageToolOneState extends State { TextEditingController _textFieldTwoController = TextEditingController(); TextEditingController _textFieldThreeController = TextEditingController(); TextEditingController _textFieldFourController = TextEditingController(); + TextEditingController _textFieldFiveController = TextEditingController(); final FocusNode searchFocusNode = FocusNode(); final _formKey = GlobalKey(); @@ -220,6 +222,20 @@ class _PackageToolOneState extends State { : null, ), const SizedBox(height: 10), + MihNumericStepper( + controller: _textFieldFiveController, + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + hintText: "Number Stepper", + requiredText: true, + minValue: 1, + // maxValue: 5, + validationOn: true, + ), + const SizedBox(height: 10), MihTextFormField( height: 250, fillColor: MzanziInnovationHub.of(context)! From 39ea6566f5c6f5f1259d346f6f35e8f046b0aadc Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 12:49:08 +0200 Subject: [PATCH 04/41] add stepper to prescription generator --- .../mih_numeric_stepper.dart | 8 +- .../pat_profile/components/prescip_input.dart | 211 ++++++++++-------- .../package_tools/patient_documents.dart | 10 +- 3 files changed, 123 insertions(+), 106 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart index c3e72ad6..30219f26 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart @@ -36,11 +36,9 @@ class _MihNumericStepperState extends State { @override void initState() { super.initState(); - setState(() { - _currentValue = - int.tryParse(widget.controller.text) ?? widget.minValue ?? 0; - widget.controller.text = _currentValue.toString(); - }); + _currentValue = + int.tryParse(widget.controller.text) ?? widget.minValue ?? 0; + widget.controller.text = _currentValue.toString(); print("Current Value: $_currentValue"); } diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart index acbb6da4..e1edd01e 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart @@ -1,10 +1,12 @@ import 'dart:convert'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_alert_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_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_numeric_stepper.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/medicine_search.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; @@ -16,7 +18,6 @@ import 'package:mzansi_innovation_hub/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/patients.dart'; import 'package:mzansi_innovation_hub/mih_objects/perscription.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:supertokens_flutter/http.dart' as http; class PrescripInput extends StatefulWidget { @@ -55,6 +56,7 @@ class PrescripInput extends StatefulWidget { class _PrescripInputState extends State { final FocusNode _focusNode = FocusNode(); final FocusNode _searchFocusNode = FocusNode(); + final _formKey = GlobalKey(); List perscriptionObjOutput = []; late double width; late double height; @@ -214,12 +216,7 @@ class _PrescripInputState extends State { } bool isFieldsFilled() { - if (widget.medicineController.text.isEmpty || - // widget.quantityController.text.isEmpty || - widget.dosageController.text.isEmpty || - widget.timesDailyController.text.isEmpty || - widget.noDaysController.text.isEmpty || - widget.noRepeatsController.text.isEmpty) { + if (widget.medicineController.text.isEmpty) { return false; } else { return true; @@ -351,92 +348,116 @@ class _PrescripInputState extends State { Widget displayMedInput() { return Column( children: [ - //const SizedBox(height: 25.0), - - MihSearchBar( - controller: widget.medicineController, - hintText: "Search Medicine", - prefixIcon: Icons.search, - fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - onPrefixIconTap: () { - getMedsPopUp(widget.medicineController); - }, - onClearIconTap: () { - widget.medicineController.clear(); - }, - searchFocusNode: _searchFocusNode, - ), - const SizedBox(height: 10.0), - - MIHDropdownField( - controller: widget.dosageController, - hintText: "Dosage", - dropdownOptions: numberOptions, - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: widget.timesDailyController, - hintText: "Times Daily", - dropdownOptions: numberOptions, - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: widget.noDaysController, - hintText: "No. Days", - dropdownOptions: numberOptions, - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: widget.noRepeatsController, - hintText: "No. Repeats", - dropdownOptions: numberOptions, - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 15.0), - MihButton( - onPressed: () { - if (isFieldsFilled()) { - setState(() { - updatePerscriptionList(); + MihForm( + formKey: _formKey, + formFields: [ + MihSearchBar( + controller: widget.medicineController, + hintText: "Search Medicine", + prefixIcon: Icons.search, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + getMedsPopUp(widget.medicineController); + }, + onClearIconTap: () { widget.medicineController.clear(); - widget.quantityController.clear(); - widget.dosageController.clear(); - widget.timesDailyController.clear(); - widget.noDaysController.clear(); - widget.noRepeatsController.clear(); - }); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } - }, - buttonColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Add", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + }, + searchFocusNode: _searchFocusNode, ), - ), - ), + const SizedBox(height: 10.0), + MihNumericStepper( + controller: widget.dosageController, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + hintText: "Dosage", + requiredText: true, + minValue: 1, + // maxValue: 5, + validationOn: true, + ), + const SizedBox(height: 10.0), + MihNumericStepper( + controller: widget.timesDailyController, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + hintText: "Times Daily", + requiredText: true, + minValue: 1, + // maxValue: 5, + validationOn: true, + ), + const SizedBox(height: 10.0), + MihNumericStepper( + controller: widget.noDaysController, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + hintText: "No. Days", + requiredText: true, + minValue: 1, + // maxValue: 5, + validationOn: true, + ), + const SizedBox(height: 10.0), + MihNumericStepper( + controller: widget.noRepeatsController, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + hintText: "No.Repeats", + requiredText: true, + minValue: 0, + // maxValue: 5, + validationOn: true, + ), + const SizedBox(height: 15.0), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + if (isFieldsFilled()) { + setState(() { + updatePerscriptionList(); + widget.medicineController.clear(); + widget.quantityController.text = "1"; + widget.dosageController.text = "1"; + widget.timesDailyController.text = "1"; + widget.noDaysController.text = "1"; + widget.noRepeatsController.text = "0"; + }); + } else { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage( + errorType: "Input Error"); + }, + ); + } + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + width: 300, + child: Text( + "Add", + style: TextStyle( + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ) ], ); } @@ -543,10 +564,8 @@ class _PrescripInputState extends State { @override Widget build(BuildContext context) { var size = MediaQuery.of(context).size; - setState(() { - width = size.width; - height = size.height; - }); + width = size.width; + height = size.height; return Wrap( direction: Axis.horizontal, alignment: WrapAlignment.center, diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart index 544bbe2c..1d874e34 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart @@ -344,11 +344,11 @@ class _PatientDocumentsState extends State { windowTitle: "Create Prescription", onWindowTapClose: () { medicineController.clear(); - quantityController.clear(); - dosageController.clear(); - timesDailyController.clear(); - noDaysController.clear(); - noRepeatsController.clear(); + quantityController.text = "1"; + dosageController.text = "1"; + timesDailyController.text = "1"; + noDaysController.text = "1"; + noRepeatsController.text = "0"; Navigator.pop(context); }, windowBody: Column( From c286635d85a99f22faa6726ecff6f935c8dfc43f Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 14:11:31 +0200 Subject: [PATCH 05/41] name hin text take null, ifg null then dont display hint --- .../mih_text_form_field.dart | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart b/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart index 082f4ee0..438f45d6 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart @@ -9,7 +9,7 @@ class MihTextFormField extends StatefulWidget { final Color inputColor; final TextEditingController controller; final bool? hasError; - final String hintText; + final String? hintText; final double? borderRadius; final bool? multiLineInput; final bool? readOnly; @@ -98,31 +98,34 @@ class _MihTextFormFieldState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - widget.hintText, - textAlign: TextAlign.left, - style: TextStyle( - color: widget.fillColor, - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - Visibility( - visible: !widget.requiredText, - child: Text( - "(Optional)", - textAlign: TextAlign.right, + Visibility( + visible: widget.hintText != null, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.hintText ?? "", + textAlign: TextAlign.left, style: TextStyle( color: widget.fillColor, fontSize: 15, fontWeight: FontWeight.bold, ), ), - ), - ], + Visibility( + visible: !widget.requiredText, + child: Text( + "(Optional)", + textAlign: TextAlign.right, + style: TextStyle( + color: widget.fillColor, + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), ), const SizedBox(height: 4), FormField( From 7184f4bb7e60e2dcf50f5b6e1d963cdc64ca9d1b Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 14:11:43 +0200 Subject: [PATCH 06/41] align hint to start --- .../mih_numeric_stepper.dart | 263 ++++++++++-------- 1 file changed, 141 insertions(+), 122 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart index 30219f26..ea14b2a0 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart @@ -44,142 +44,161 @@ class _MihNumericStepperState extends State { @override Widget build(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, + return Column( children: [ - Column( + Row( 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), - ), - ], - ), - child: Padding( - padding: const EdgeInsets.only( - top: 2.0, - left: 5.0, - ), - child: SizedBox( - width: 40, - child: IconButton.filled( - style: ButtonStyle( - backgroundColor: - WidgetStateProperty.all(widget.fillColor), - ), - color: widget.inputColor, - iconSize: 20, - onPressed: () { - print("Current Value: $_currentValue"); - if (_currentValue >= (widget.minValue ?? 0)) { - setState(() { - widget.controller.text = - (_currentValue - 1).toString(); - _currentValue = int.tryParse(widget.controller.text)!; - }); - } - print("New Current Value: $_currentValue"); - }, - icon: const Icon( - Icons.remove, - ), - ), - ), - ), - ), - Visibility( - visible: _currentValue < (widget.minValue ?? 0), - child: const SizedBox( - height: 21, + Text( + widget.hintText, + style: TextStyle( + fontWeight: FontWeight.bold, + color: widget.fillColor, + fontSize: 15, ), ), ], ), - const SizedBox(width: 5), - Expanded( - child: MihTextFormField( - width: widget.width, - fillColor: widget.fillColor, - inputColor: widget.inputColor, - controller: widget.controller, - hintText: widget.hintText, - requiredText: widget.requiredText, - readOnly: true, - numberMode: true, - validator: (value) { - if (widget.validationOn) { - return MihValidationServices() - .validateNumber(value, widget.minValue, widget.maxValue); - } - return null; - }, - ), - ), - Column( + const SizedBox(height: 4), + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, 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), + Column( + 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), + ), + ], ), - ], - ), - child: Padding( - padding: const EdgeInsets.only( - top: 2.0, - left: 5.0, - ), - child: SizedBox( - width: 40, - child: IconButton.filled( - style: ButtonStyle( - backgroundColor: - WidgetStateProperty.all(widget.fillColor), + child: Padding( + padding: const EdgeInsets.only( + top: 2.0, + left: 5.0, ), - color: widget.inputColor, - iconSize: 20, - onPressed: () { - print("Current Value: $_currentValue"); - if (widget.maxValue == null || - _currentValue <= widget.maxValue!) { - setState(() { - widget.controller.text = - (_currentValue + 1).toString(); - _currentValue = int.tryParse(widget.controller.text)!; - }); - } - print("New Current Value: $_currentValue"); - }, - icon: const Icon( - Icons.add, + child: SizedBox( + width: 40, + child: IconButton.filled( + style: ButtonStyle( + backgroundColor: + WidgetStateProperty.all(widget.fillColor), + ), + color: widget.inputColor, + iconSize: 20, + onPressed: () { + print("Current Value: $_currentValue"); + if (_currentValue >= (widget.minValue ?? 0)) { + setState(() { + widget.controller.text = + (_currentValue - 1).toString(); + _currentValue = + int.tryParse(widget.controller.text)!; + }); + } + print("New Current Value: $_currentValue"); + }, + icon: const Icon( + Icons.remove, + ), + ), ), ), ), + Visibility( + visible: _currentValue < (widget.minValue ?? 0), + child: const SizedBox( + height: 21, + ), + ), + ], + ), + const SizedBox(width: 5), + Expanded( + child: MihTextFormField( + width: widget.width, + fillColor: widget.fillColor, + inputColor: widget.inputColor, + controller: widget.controller, + hintText: null, + requiredText: widget.requiredText, + readOnly: true, + numberMode: true, + validator: (value) { + if (widget.validationOn) { + return MihValidationServices().validateNumber( + value, widget.minValue, widget.maxValue); + } + return null; + }, ), ), - Visibility( - visible: _currentValue < (widget.minValue ?? 0), - child: const SizedBox( - height: 20, - ), + Column( + 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), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.only( + top: 2.0, + left: 5.0, + ), + child: SizedBox( + width: 40, + child: IconButton.filled( + style: ButtonStyle( + backgroundColor: + WidgetStateProperty.all(widget.fillColor), + ), + color: widget.inputColor, + iconSize: 20, + onPressed: () { + print("Current Value: $_currentValue"); + if (widget.maxValue == null || + _currentValue <= widget.maxValue!) { + setState(() { + widget.controller.text = + (_currentValue + 1).toString(); + _currentValue = + int.tryParse(widget.controller.text)!; + }); + } + print("New Current Value: $_currentValue"); + }, + icon: const Icon( + Icons.add, + ), + ), + ), + ), + ), + Visibility( + visible: _currentValue < (widget.minValue ?? 0), + child: const SizedBox( + height: 20, + ), + ), + ], ), ], ), From 9bc215bce08d2626cb5c3c86dd4dd2724e3ebd66 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 14:11:56 +0200 Subject: [PATCH 07/41] create mih toggle --- .../mih_package_components/mih_toggle.dart | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Frontend/lib/mih_components/mih_package_components/mih_toggle.dart diff --git a/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart b/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart new file mode 100644 index 00000000..9eda3852 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +class MihToggle extends StatefulWidget { + final String hintText; + final bool initialPostion; + final Color fillColor; + final Color secondaryFillColor; + final void Function(bool) onChange; + const MihToggle({ + super.key, + required this.hintText, + required this.initialPostion, + required this.fillColor, + required this.secondaryFillColor, + required this.onChange, + }); + + @override + State createState() => _MihToggleState(); +} + +class _MihToggleState extends State { + late bool togglePosition; + + @override + void initState() { + super.initState(); + setState(() { + togglePosition = widget.initialPostion; + }); + } + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Text( + widget.hintText, + style: TextStyle( + fontWeight: FontWeight.bold, + color: widget.fillColor, + fontSize: 15, + ), + ), + ), + const SizedBox(width: 10), + Switch( + value: widget.initialPostion, + activeColor: widget.secondaryFillColor, + activeTrackColor: widget.fillColor, + inactiveThumbColor: widget.fillColor, + inactiveTrackColor: widget.secondaryFillColor, + onChanged: widget.onChange, + ), + ], + ); + } +} From eace2592f978cdc96810b2aefb4b94251893d049 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 14:12:37 +0200 Subject: [PATCH 08/41] add toggle to test --- .../package_tools/package_tool_one.dart | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 6d917af4..8262e0fe 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 @@ -16,6 +16,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_image_display.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; class PackageToolOne extends StatefulWidget { const PackageToolOne({super.key}); @@ -37,6 +38,7 @@ class _PackageToolOneState extends State { TextEditingController _textFieldThreeController = TextEditingController(); TextEditingController _textFieldFourController = TextEditingController(); TextEditingController _textFieldFiveController = TextEditingController(); + bool switchpositioin = true; final FocusNode searchFocusNode = FocusNode(); final _formKey = GlobalKey(); @@ -236,6 +238,22 @@ class _PackageToolOneState extends State { validationOn: true, ), const SizedBox(height: 10), + MihToggle( + hintText: "Toggle", + initialPostion: switchpositioin, + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onChange: (value) { + setState(() { + switchpositioin = value; + }); + print("Toggle Value: $switchpositioin"); + }, + ), + const SizedBox(height: 10), MihTextFormField( height: 250, fillColor: MzanziInnovationHub.of(context)! From eca03eaffd670c2514dd6f2d12cb2c4c6f0d7c16 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 14:13:04 +0200 Subject: [PATCH 09/41] add togle top calc: tip calc --- .../calculator/package_tools/tip_calc.dart | 99 +++++++++++-------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart b/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart index d8edef5d..6ba27979 100644 --- a/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart +++ b/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart @@ -1,16 +1,17 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_numeric_stepper.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:math_expressions/math_expressions.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; class TipCalc extends StatefulWidget { const TipCalc({super.key}); @@ -25,6 +26,8 @@ class _TipCalcState extends State { TextEditingController splitBillController = TextEditingController(); TextEditingController noPeopleController = TextEditingController(); final ValueNotifier splitValue = ValueNotifier(""); + final ValueNotifier splitBoolValue = ValueNotifier(false); + late bool splitPosition; final _formKey = GlobalKey(); String tip = ""; String total = ""; @@ -230,6 +233,7 @@ class _TipCalcState extends State { void initState() { super.initState(); splitBillController.text = "No"; + splitPosition = false; splitBillController.addListener(splitSelected); } @@ -269,13 +273,6 @@ class _TipCalcState extends State { return MihValidationServices().isEmpty(value); }, ), - // MIHNumberField( - // controller: billAmountController, - // hintText: "Bill Amount", - // editable: true, - // required: true, - // enableDecimal: true, - // ), const SizedBox(height: 10), MihTextFormField( fillColor: @@ -291,23 +288,36 @@ class _TipCalcState extends State { return MihValidationServices().isEmpty(value); }, ), - // MIHNumberField( - // controller: tipPercentageController, - // hintText: "Tip %", - // editable: true, - // required: true, - // enableDecimal: false, - // ), - const SizedBox(height: 20), - MIHDropdownField( - controller: splitBillController, - hintText: "Split Bill", - dropdownOptions: const ["Yes", "No"], - required: true, - editable: true, - enableSearch: false, - ), const SizedBox(height: 10), + MihToggle( + hintText: "Split Bill", + initialPostion: splitPosition, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onChange: (value) { + if (value) { + setState(() { + splitBillController.text = "Yes"; + splitPosition = value; + }); + } else { + setState(() { + splitBillController.text = "No"; + splitPosition = value; + }); + } + }, + ), + // MIHDropdownField( + // controller: splitBillController, + // hintText: "Split Bill", + // dropdownOptions: const ["Yes", "No"], + // required: true, + // editable: true, + // enableSearch: false, + // ), ValueListenableBuilder( valueListenable: splitValue, builder: (BuildContext context, String value, Widget? child) { @@ -316,33 +326,40 @@ class _TipCalcState extends State { visible: temp == "Yes", child: Column( children: [ - MihTextFormField( + MihNumericStepper( + controller: noPeopleController, fillColor: MzanziInnovationHub.of(context)! .theme .secondaryColor(), inputColor: MzanziInnovationHub.of(context)! .theme .primaryColor(), - controller: noPeopleController, - multiLineInput: false, + hintText: "No. People", requiredText: temp == "Yes", - hintText: "No. of People", - numberMode: true, - validator: (validationValue) { - if (temp == "Yes") { - return MihValidationServices() - .isEmpty(validationValue); - } else { - return null; - } - }, + minValue: 2, + // maxValue: 5, + validationOn: true, ), - // MIHNumberField( + // MihTextFormField( + // fillColor: MzanziInnovationHub.of(context)! + // .theme + // .secondaryColor(), + // inputColor: MzanziInnovationHub.of(context)! + // .theme + // .primaryColor(), // controller: noPeopleController, + // multiLineInput: false, + // requiredText: temp == "Yes", // hintText: "No. of People", - // editable: true, - // required: true, - // enableDecimal: false, + // numberMode: true, + // validator: (validationValue) { + // if (temp == "Yes") { + // return MihValidationServices() + // .isEmpty(validationValue); + // } else { + // return null; + // } + // }, // ), const SizedBox(height: 10), ], From 53a8a0f2482fb69d651e6577c67c0e46a7e2d590 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 14:13:19 +0200 Subject: [PATCH 10/41] add togle top personal profle --- .../package_tools/mih_personal_profile.dart | 60 ++++++++++++------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart index 973b1f92..d2b731ec 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart @@ -12,6 +12,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; @@ -332,30 +333,43 @@ class _MihPersonalProfileState extends State { }, ), const SizedBox(height: 10.0), - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Text( - "Activate Business Account", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 20, - ), - ), - const SizedBox( - width: 10, - ), - Switch( - value: businessUser, - onChanged: (bool value) { - setState(() { - businessUser = value; - }); - }, - ), - ], + MihToggle( + hintText: "Activate Business Account", + initialPostion: businessUser, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onChange: (value) { + setState(() { + businessUser = value; + }); + }, ), + // Row( + // mainAxisAlignment: MainAxisAlignment.start, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // const Text( + // "Activate Business Account", + // style: TextStyle( + // fontWeight: FontWeight.bold, + // fontSize: 20, + // ), + // ), + // const SizedBox( + // width: 10, + // ), + // Switch( + // value: businessUser, + // onChanged: (bool value) { + // setState(() { + // businessUser = value; + // }); + // }, + // ), + // ], + // ), const SizedBox(height: 30.0), Center( child: MihButton( From 7c223e088cf9161ec53b468bb722bec940c1b757 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 14:15:09 +0200 Subject: [PATCH 11/41] . --- .../mih_packages/calculator/package_tools/tip_calc.dart | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart b/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart index 6ba27979..546fe21a 100644 --- a/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart +++ b/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart @@ -26,7 +26,6 @@ class _TipCalcState extends State { TextEditingController splitBillController = TextEditingController(); TextEditingController noPeopleController = TextEditingController(); final ValueNotifier splitValue = ValueNotifier(""); - final ValueNotifier splitBoolValue = ValueNotifier(false); late bool splitPosition; final _formKey = GlobalKey(); String tip = ""; @@ -310,14 +309,6 @@ class _TipCalcState extends State { } }, ), - // MIHDropdownField( - // controller: splitBillController, - // hintText: "Split Bill", - // dropdownOptions: const ["Yes", "No"], - // required: true, - // editable: true, - // enableSearch: false, - // ), ValueListenableBuilder( valueListenable: splitValue, builder: (BuildContext context, String value, Widget? child) { From fba90d5925dc9e025d4feddba24547a4b8864b62 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 15:01:38 +0200 Subject: [PATCH 12/41] add readonly mode to toggle --- .../mih_package_components/mih_toggle.dart | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart b/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart index 9eda3852..42ff508c 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart @@ -5,6 +5,7 @@ class MihToggle extends StatefulWidget { final bool initialPostion; final Color fillColor; final Color secondaryFillColor; + final bool? readOnly; final void Function(bool) onChange; const MihToggle({ super.key, @@ -12,6 +13,7 @@ class MihToggle extends StatefulWidget { required this.initialPostion, required this.fillColor, required this.secondaryFillColor, + this.readOnly, required this.onChange, }); @@ -49,11 +51,20 @@ class _MihToggleState extends State { const SizedBox(width: 10), Switch( value: widget.initialPostion, - activeColor: widget.secondaryFillColor, - activeTrackColor: widget.fillColor, - inactiveThumbColor: widget.fillColor, - inactiveTrackColor: widget.secondaryFillColor, - onChanged: widget.onChange, + activeColor: + widget.readOnly == true ? Colors.grey : widget.secondaryFillColor, + activeTrackColor: + widget.readOnly == true ? Colors.grey.shade400 : widget.fillColor, + inactiveThumbColor: + widget.readOnly == true ? Colors.grey : widget.fillColor, + inactiveTrackColor: widget.readOnly == true + ? Colors.grey.shade400 + : widget.secondaryFillColor, + // activeColor: widget.secondaryFillColor, + // activeTrackColor: widget.fillColor, + // inactiveThumbColor: widget.fillColor, + // inactiveTrackColor: widget.secondaryFillColor, + onChanged: widget.readOnly != true ? widget.onChange : null, ), ], ); From 7cc81ca1fa6cd03d1419afdbd5c7c0cc7e1bfcd7 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 15:01:47 +0200 Subject: [PATCH 13/41] update example --- .../Example/package_tools/package_tool_one.dart | 1 + 1 file changed, 1 insertion(+) 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 8262e0fe..d198072c 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 @@ -246,6 +246,7 @@ class _PackageToolOneState extends State { .secondaryColor(), secondaryFillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + readOnly: true, onChange: (value) { setState(() { switchpositioin = value; From 9b6b335f128c02b1b8a21efcd198df6cec14f111 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 9 Jun 2025 15:01:57 +0200 Subject: [PATCH 14/41] update patien profile --- .../package_tools/patient_info.dart | 47 ++++++++++--- .../pat_profile/patient_add.dart | 59 ++++++++++++---- .../pat_profile/patient_edit.dart | 68 +++++++++++++++---- 3 files changed, 139 insertions(+), 35 deletions(-) diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_info.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_info.dart index 320b3fd6..0f817e90 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_info.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_info.dart @@ -5,6 +5,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_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:mzansi_innovation_hub/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_objects/patients.dart'; @@ -39,8 +40,9 @@ class _PatientInfoState extends State { final medMainMemController = TextEditingController(); final medAidCodeController = TextEditingController(); final _formKey = GlobalKey(); - double textFieldWidth = 500; + double textFieldWidth = 300; late String medAid; + late bool medAidPosition; Widget getPatientDetailsField() { return Center( @@ -146,16 +148,37 @@ class _PatientInfoState extends State { medAidDet.add( SizedBox( width: textFieldWidth, - child: MihTextFormField( - // width: textFieldWidth, - fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - controller: medAidController, - multiLineInput: false, - requiredText: true, - readOnly: true, + child: MihToggle( hintText: "Medical Aid", + initialPostion: medAidPosition, + fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + readOnly: true, + onChange: (value) { + if (value) { + setState(() { + medAidController.text = "Yes"; + medAidPosition = value; + }); + } else { + setState(() { + medAidController.text = "No"; + medAidPosition = value; + }); + } + }, ), + // MihTextFormField( + // // width: textFieldWidth, + // fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + // inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + // controller: medAidController, + // multiLineInput: false, + // requiredText: true, + // readOnly: true, + // hintText: "Medical Aid", + // ), ), ); bool req; @@ -216,6 +239,7 @@ class _PatientInfoState extends State { Visibility( visible: req, child: SizedBox( + width: textFieldWidth, child: MihTextFormField( // width: textFieldWidth, fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), @@ -299,6 +323,11 @@ class _PatientInfoState extends State { TextEditingValue(text: widget.selectedPatient.medical_aid_code); medAid = widget.selectedPatient.medical_aid; }); + if (medAid == "Yes") { + medAidPosition = true; + } else { + medAidPosition = false; + } super.initState(); } diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_add.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_add.dart index 4afaabfa..7cebc9a8 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_add.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_add.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_header.dart'; @@ -11,6 +10,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_layout_build import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; @@ -46,6 +46,8 @@ class _AddPatientState extends State { final medMainMemController = TextEditingController(); final medAidCodeController = TextEditingController(); + late bool medAidPosition; + late bool medMainMemberPosition; final baseAPI = AppEnviroment.baseApiUrl; late int futureDocOfficeId; //late bool medRequired; @@ -297,13 +299,26 @@ class _AddPatientState extends State { .theme .secondaryColor()), const SizedBox(height: 10.0), - MIHDropdownField( - controller: medAidController, + MihToggle( hintText: "Medical Aid", - editable: true, - required: true, - enableSearch: false, - dropdownOptions: const ["Yes", "No"], + initialPostion: medAidPosition, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onChange: (value) { + if (value) { + setState(() { + medAidController.text = "Yes"; + medAidPosition = value; + }); + } else { + setState(() { + medAidController.text = "No"; + medAidPosition = value; + }); + } + }, ), ValueListenableBuilder( valueListenable: medRequired, @@ -313,13 +328,28 @@ class _AddPatientState extends State { child: Column( children: [ const SizedBox(height: 10.0), - MIHDropdownField( - controller: medMainMemController, + MihToggle( hintText: "Main Member", - editable: value, - required: value, - enableSearch: false, - dropdownOptions: const ["Yes", "No"], + initialPostion: medMainMemberPosition, + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + secondaryFillColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + onChange: (value) { + if (value) { + setState(() { + medMainMemController.text = "Yes"; + medMainMemberPosition = value; + }); + } else { + setState(() { + medMainMemController.text = "No"; + medMainMemberPosition = value; + }); + } + }, ), const SizedBox(height: 10.0), MihTextFormField( @@ -520,7 +550,10 @@ class _AddPatientState extends State { fnameController.text = widget.signedInUser.fname; lnameController.text = widget.signedInUser.lname; emailController.text = widget.signedInUser.email; + medAidPosition = false; + medMainMemberPosition = false; medAidController.text = "No"; + medMainMemController.text = "No"; }); super.initState(); } diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_edit.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_edit.dart index 63dd4f86..19e25cee 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_edit.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_edit.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_header.dart'; @@ -11,6 +10,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_layout_build import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; @@ -54,6 +54,8 @@ class _EditPatientState extends State { final apiUrlDelete = "${AppEnviroment.baseApiUrl}/patients/delete/"; final _formKey = GlobalKey(); + late bool medAidPosition; + late bool medMainMemberPosition; late int futureDocOfficeId; late String userEmail; // bool medRequired = false; @@ -511,13 +513,26 @@ class _EditPatientState extends State { .theme .secondaryColor()), const SizedBox(height: 10.0), - MIHDropdownField( - controller: medAidController, + MihToggle( hintText: "Medical Aid", - editable: true, - required: true, - enableSearch: false, - dropdownOptions: const ["Yes", "No"], + initialPostion: medAidPosition, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onChange: (value) { + if (value) { + setState(() { + medAidController.text = "Yes"; + medAidPosition = value; + }); + } else { + setState(() { + medAidController.text = "No"; + medAidPosition = value; + }); + } + }, ), ValueListenableBuilder( valueListenable: medRequired, @@ -527,13 +542,28 @@ class _EditPatientState extends State { child: Column( children: [ const SizedBox(height: 10.0), - MIHDropdownField( - controller: medMainMemController, + MihToggle( hintText: "Main Member", - editable: value, - required: value, - enableSearch: false, - dropdownOptions: const ["Yes", "No"], + initialPostion: medMainMemberPosition, + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + secondaryFillColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + onChange: (value) { + if (value) { + setState(() { + medMainMemController.text = "Yes"; + medMainMemberPosition = value; + }); + } else { + setState(() { + medMainMemController.text = "No"; + medMainMemberPosition = value; + }); + } + }, ), const SizedBox(height: 10.0), MihTextFormField( @@ -747,6 +777,18 @@ class _EditPatientState extends State { medAidCodeController.text = widget.selectedPatient.medical_aid_code; }); + if (medAidController.text == "Yes") { + medAidPosition = true; + } else { + medAidPosition = false; + medAidController.text = "No"; + } + if (medMainMemController.text == "Yes") { + medMainMemberPosition = true; + } else { + medMainMemberPosition = false; + medMainMemController.text = "No"; + } super.initState(); } From 7fb6011ec1b90f9a6b1718d1442cc96b9c897de2 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 09:33:53 +0200 Subject: [PATCH 15/41] Change label size --- .../mih_numeric_stepper.dart | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart index ea14b2a0..43ba2f03 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart @@ -53,7 +53,7 @@ class _MihNumericStepperState extends State { style: TextStyle( fontWeight: FontWeight.bold, color: widget.fillColor, - fontSize: 15, + fontSize: 18, ), ), ], @@ -114,14 +114,15 @@ class _MihNumericStepperState extends State { ), ), Visibility( - visible: _currentValue < (widget.minValue ?? 0), + visible: _currentValue < (widget.minValue ?? 0) || + _currentValue > widget.maxValue!, child: const SizedBox( height: 21, ), ), ], ), - const SizedBox(width: 5), + const SizedBox(width: 15), Expanded( child: MihTextFormField( width: widget.width, @@ -132,6 +133,7 @@ class _MihNumericStepperState extends State { requiredText: widget.requiredText, readOnly: true, numberMode: true, + textIputAlignment: TextAlign.center, validator: (value) { if (widget.validationOn) { return MihValidationServices().validateNumber( @@ -141,6 +143,7 @@ class _MihNumericStepperState extends State { }, ), ), + const SizedBox(width: 10), Column( children: [ Container( @@ -193,9 +196,10 @@ class _MihNumericStepperState extends State { ), ), Visibility( - visible: _currentValue < (widget.minValue ?? 0), + visible: _currentValue < (widget.minValue ?? 0) || + _currentValue > widget.maxValue!, child: const SizedBox( - height: 20, + height: 21, ), ), ], From 11fc60627028dde09ffba8e593e948da23d1b830 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 09:34:36 +0200 Subject: [PATCH 16/41] update font --- .../mih_radio_options.dart | 130 ++++++++++++++++++ .../mih_text_form_field.dart | 9 +- .../mih_package_components/mih_toggle.dart | 2 +- 3 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_package_components/mih_radio_options.dart diff --git a/Frontend/lib/mih_components/mih_package_components/mih_radio_options.dart b/Frontend/lib/mih_components/mih_package_components/mih_radio_options.dart new file mode 100644 index 00000000..4eb44ee2 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_radio_options.dart @@ -0,0 +1,130 @@ +import 'package:flutter/material.dart'; + +class MihRadioOptions extends StatefulWidget { + final TextEditingController controller; + final String hintText; + final Color fillColor; + final Color secondaryFillColor; + final bool requiredText; + final List radioOptions; + const MihRadioOptions({ + super.key, + required this.controller, + required this.hintText, + required this.fillColor, + required this.secondaryFillColor, + required this.requiredText, + required this.radioOptions, + }); + + @override + State createState() => _MihRadioOptionsState(); +} + +class _MihRadioOptionsState extends State { + late String _currentSelection; + + @override + void initState() { + super.initState(); + setState(() { + _currentSelection = widget.radioOptions[0]; + }); + } + + Widget displayRadioOptions() { + return Material( + elevation: 4.0, + borderRadius: BorderRadius.circular(8.0), + child: Container( + decoration: BoxDecoration( + color: widget.fillColor, + borderRadius: BorderRadius.circular(8.0), + ), + child: Column( + children: widget.radioOptions.map((option) { + return GestureDetector( + onTap: () { + setState(() { + int index = widget.radioOptions + .indexWhere((element) => element == option); + _currentSelection = widget.radioOptions[index]; + widget.controller.text = option; + }); + }, + child: Row( + children: [ + const SizedBox(width: 10), + Expanded( + child: Text( + option, + style: TextStyle( + color: widget.secondaryFillColor, + fontWeight: FontWeight.w500, + fontSize: 15, + ), + ), + ), + Radio( + value: option, + groupValue: _currentSelection, + onChanged: (value) { + setState(() { + _currentSelection = value!; + widget.controller.text = value; + }); + }, + activeColor: widget.secondaryFillColor, + fillColor: WidgetStateProperty.resolveWith( + (Set states) { + if (states.contains(WidgetState.selected)) { + return widget.secondaryFillColor; // Color when selected + } + return widget.secondaryFillColor; + }), + ), + ], + ), + ); + }).toList(), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.hintText, + textAlign: TextAlign.left, + style: TextStyle( + color: widget.fillColor, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + Visibility( + visible: !widget.requiredText, + child: Text( + "(Optional)", + textAlign: TextAlign.right, + style: TextStyle( + color: widget.fillColor, + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 4), + displayRadioOptions(), + ], + ); + } +} diff --git a/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart b/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart index 438f45d6..7675561b 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart @@ -19,6 +19,7 @@ class MihTextFormField extends StatefulWidget { final FormFieldValidator? validator; final List? autofillHints; final double? elevation; + final TextAlign? textIputAlignment; const MihTextFormField({ Key? key, @@ -38,6 +39,7 @@ class MihTextFormField extends StatefulWidget { this.validator, this.autofillHints, this.elevation, + this.textIputAlignment, }) : super(key: key); @override @@ -108,7 +110,7 @@ class _MihTextFormFieldState extends State { textAlign: TextAlign.left, style: TextStyle( color: widget.fillColor, - fontSize: 15, + fontSize: 18, fontWeight: FontWeight.bold, ), ), @@ -144,13 +146,14 @@ class _MihTextFormFieldState extends State { BorderRadius.circular(widget.borderRadius ?? 8.0), child: SizedBox( height: widget.height != null - ? widget.height! - 25 + ? widget.height! - 30 : null, child: TextFormField( controller: widget.controller, cursorColor: widget.inputColor, autofillHints: widget.autofillHints, - textAlign: TextAlign.start, + textAlign: + widget.textIputAlignment ?? TextAlign.start, textAlignVertical: widget.multiLineInput == true ? TextAlignVertical.top : TextAlignVertical.center, diff --git a/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart b/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart index 42ff508c..5872bf6c 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart @@ -44,7 +44,7 @@ class _MihToggleState extends State { style: TextStyle( fontWeight: FontWeight.bold, color: widget.fillColor, - fontSize: 15, + fontSize: 18, ), ), ), From 949bb7277d4677bb55b1803de6013876824452d5 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 11:09:09 +0200 Subject: [PATCH 17/41] fiux stepper in tip calc --- .../mih_numeric_stepper.dart | 6 ++-- .../calculator/package_tools/tip_calc.dart | 35 +++++++++++++------ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart index 43ba2f03..3afeaf06 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart @@ -115,7 +115,8 @@ class _MihNumericStepperState extends State { ), Visibility( visible: _currentValue < (widget.minValue ?? 0) || - _currentValue > widget.maxValue!, + (widget.maxValue != null && + _currentValue > widget.maxValue!), child: const SizedBox( height: 21, ), @@ -197,7 +198,8 @@ class _MihNumericStepperState extends State { ), Visibility( visible: _currentValue < (widget.minValue ?? 0) || - _currentValue > widget.maxValue!, + (widget.maxValue != null && + _currentValue > widget.maxValue!), child: const SizedBox( height: 21, ), diff --git a/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart b/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart index 546fe21a..b4191d3f 100644 --- a/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart +++ b/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart @@ -232,6 +232,7 @@ class _TipCalcState extends State { void initState() { super.initState(); splitBillController.text = "No"; + noPeopleController.text = "2"; splitPosition = false; splitBillController.addListener(splitSelected); } @@ -296,17 +297,29 @@ class _TipCalcState extends State { secondaryFillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), onChange: (value) { - if (value) { - setState(() { - splitBillController.text = "Yes"; - splitPosition = value; - }); - } else { - setState(() { - splitBillController.text = "No"; - splitPosition = value; - }); - } + setState(() { + splitBillController.text = value ? "Yes" : "No"; + splitPosition = value; + if (value) { + noPeopleController.text = + noPeopleController.text.isEmpty + ? "2" + : noPeopleController.text; + } else { + noPeopleController.clear(); + } + }); + // if (value) { + // setState(() { + // splitBillController.text = "Yes"; + // splitPosition = value; + // }); + // } else { + // setState(() { + // splitBillController.text = "No"; + // splitPosition = value; + // }); + // } }, ), ValueListenableBuilder( From f61be23739c9e00268ba8eb270030f4ef54ed9c2 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 11:09:23 +0200 Subject: [PATCH 18/41] add radio button to claim generation --- .../mih_radio_options.dart | 108 ++++++++------- .../components/Claim_Statement_Window.dart | 127 ++++++++++++------ 2 files changed, 146 insertions(+), 89 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_radio_options.dart b/Frontend/lib/mih_components/mih_package_components/mih_radio_options.dart index 4eb44ee2..5f7dfa40 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_radio_options.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_radio_options.dart @@ -22,17 +22,32 @@ class MihRadioOptions extends StatefulWidget { } class _MihRadioOptionsState extends State { - late String _currentSelection; + // late String _currentSelection; @override void initState() { super.initState(); - setState(() { - _currentSelection = widget.radioOptions[0]; - }); + if (widget.controller.text.isEmpty && widget.radioOptions.isNotEmpty) { + widget.controller.text = widget.radioOptions[0]; + } + // else{ + // int index = widget.radioOptions + // .indexWhere((element) => element == option); + // _currentSelection = widget.radioOptions[index]; + // widget.controller.text = option; + + // } + // _currentSelection = widget.radioOptions[0]; } - Widget displayRadioOptions() { +// The method to handle a change in selection. + void _onChanged(String? value) { + if (value != null) { + widget.controller.text = value; + } + } + + Widget displayRadioOptions(String selection) { return Material( elevation: 4.0, borderRadius: BorderRadius.circular(8.0), @@ -45,12 +60,7 @@ class _MihRadioOptionsState extends State { children: widget.radioOptions.map((option) { return GestureDetector( onTap: () { - setState(() { - int index = widget.radioOptions - .indexWhere((element) => element == option); - _currentSelection = widget.radioOptions[index]; - widget.controller.text = option; - }); + _onChanged(option); }, child: Row( children: [ @@ -67,13 +77,8 @@ class _MihRadioOptionsState extends State { ), Radio( value: option, - groupValue: _currentSelection, - onChanged: (value) { - setState(() { - _currentSelection = value!; - widget.controller.text = value; - }); - }, + groupValue: selection, + onChanged: _onChanged, activeColor: widget.secondaryFillColor, fillColor: WidgetStateProperty.resolveWith( (Set states) { @@ -94,37 +99,42 @@ class _MihRadioOptionsState extends State { @override Widget build(BuildContext context) { - return Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - widget.hintText, - textAlign: TextAlign.left, - style: TextStyle( - color: widget.fillColor, - fontSize: 18, - fontWeight: FontWeight.bold, + return AnimatedBuilder( + animation: widget.controller, + builder: (context, child) { + final currentSelection = widget.controller.text; + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.hintText, + textAlign: TextAlign.left, + style: TextStyle( + color: widget.fillColor, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + Visibility( + visible: !widget.requiredText, + child: Text( + "(Optional)", + textAlign: TextAlign.right, + style: TextStyle( + color: widget.fillColor, + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + ], ), - ), - Visibility( - visible: !widget.requiredText, - child: Text( - "(Optional)", - textAlign: TextAlign.right, - style: TextStyle( - color: widget.fillColor, - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - const SizedBox(height: 4), - displayRadioOptions(), - ], - ); + const SizedBox(height: 4), + displayRadioOptions(currentSelection), + ], + ); + }); } } diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart index 61e185c9..a3959a58 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart @@ -1,15 +1,13 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_claim_statement_generation_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_icd10_code_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_date_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_radio_options.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; @@ -93,13 +91,15 @@ class _ClaimStatementWindowState extends State { MihForm( formKey: _formKey, formFields: [ - MIHDropdownField( + MihRadioOptions( controller: _docTypeController, hintText: "Document Type", - dropdownOptions: const ["Claim", "Statement"], - required: true, - editable: true, - enableSearch: false, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + requiredText: true, + radioOptions: const ["Claim", "Statement"], ), const SizedBox(height: 10), Center( @@ -124,17 +124,19 @@ class _ClaimStatementWindowState extends State { required: true, ), const SizedBox(height: 10), - MIHDropdownField( + MihRadioOptions( controller: _serviceDescController, - hintText: "Service Decription", - dropdownOptions: const [ + hintText: "Serviced Description", + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + requiredText: true, + radioOptions: const [ "Consultation", "Procedure", "Other", ], - required: true, - editable: true, - enableSearch: false, ), const SizedBox(height: 10), ValueListenableBuilder( @@ -144,29 +146,37 @@ class _ClaimStatementWindowState extends State { switch (value) { case 'Consultation': returnWidget = Column( + key: const ValueKey('consultation_fields'), // Added key children: [ - SizedBox( - child: MIHDropdownField( - controller: _serviceDescOptionsController, - hintText: "Consultation Type", - dropdownOptions: const [ - "General Consultation", - "Follow-Up Consultation", - "Specialist Consultation", - "Emergency Consultation", - ], - required: true, - editable: true, - enableSearch: false, - ), + MihRadioOptions( + key: const ValueKey('consultation_type_dropdown'), + controller: _serviceDescOptionsController, + hintText: "Consultation Type", + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + secondaryFillColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + requiredText: true, + radioOptions: const [ + "General Consultation", + "Follow-Up Consultation", + "Specialist Consultation", + "Emergency Consultation", + ], ), const SizedBox(height: 10), ], ); + break; case 'Procedure': returnWidget = Column( + key: const ValueKey('procedure_fields'), // Added key children: [ MihTextFormField( + key: const ValueKey( + 'procedure_name_field'), // Added key fillColor: MzanziInnovationHub.of(context)! .theme .secondaryColor(), @@ -183,6 +193,8 @@ class _ClaimStatementWindowState extends State { ), const SizedBox(height: 10), MihTextFormField( + key: const ValueKey( + 'procedure_additional_info_field'), // Added key fillColor: MzanziInnovationHub.of(context)! .theme .secondaryColor(), @@ -192,7 +204,7 @@ class _ClaimStatementWindowState extends State { controller: _proceedureAdditionalInfoController, multiLineInput: false, requiredText: true, - hintText: "Additional Information", + hintText: "Additional Procedure Information", validator: (value) { return MihValidationServices().isEmpty(value); }, @@ -200,10 +212,14 @@ class _ClaimStatementWindowState extends State { const SizedBox(height: 15), ], ); + break; case 'Other': returnWidget = Column( + key: const ValueKey('other_fields'), // Added key children: [ MihTextFormField( + key: const ValueKey( + 'other_service_description_field'), // Added key fillColor: MzanziInnovationHub.of(context)! .theme .secondaryColor(), @@ -221,8 +237,10 @@ class _ClaimStatementWindowState extends State { const SizedBox(height: 10), ], ); + break; default: - returnWidget = const SizedBox(); + returnWidget = const SizedBox( + key: const ValueKey('empty_fields')); // Added key } return returnWidget; }, @@ -233,7 +251,7 @@ class _ClaimStatementWindowState extends State { alignment: Alignment.centerLeft, child: Text("ICD-10 Code & Description", style: TextStyle( - fontSize: 15, + fontSize: 18, fontWeight: FontWeight.bold, color: MzanziInnovationHub.of(context)! .theme @@ -384,16 +402,25 @@ class _ClaimStatementWindowState extends State { } void serviceDescriptionSelected() { - if (_serviceDescController.text.isNotEmpty) { - serviceDesc.value = _serviceDescController.text; + String selectedType = _serviceDescController.text; + serviceDesc.value = selectedType; + if (selectedType == 'Consultation') { + _prcedureNameController.clear(); + _proceedureAdditionalInfoController.clear(); + } else if (selectedType == 'Procedure') { + _serviceDescOptionsController.clear(); + } else if (selectedType == 'Other') { + _prcedureNameController.clear(); + _proceedureAdditionalInfoController.clear(); } else { - serviceDesc.value = ""; + _prcedureNameController.clear(); + _proceedureAdditionalInfoController.clear(); + _serviceDescOptionsController.clear(); } } void hasMedAid() { if (_medAidController.text.isNotEmpty) { - medAid.value = _medAidController.text; } else { medAid.value = ""; } @@ -403,12 +430,26 @@ class _ClaimStatementWindowState extends State { if (_docTypeController.text.isEmpty || _serviceDateController.text.isEmpty || _icd10CodeController.text.isEmpty || - _amountController.text.isEmpty || - _serviceDescOptionsController.text.isEmpty) { + _amountController.text.isEmpty) { return false; - } else { - return true; } + switch (_serviceDescController.text) { + case 'Consultation': + case 'Other': + if (_serviceDescOptionsController.text.isEmpty) { + return false; + } + break; + case 'Procedure': + if (_prcedureNameController.text.isEmpty || + _proceedureAdditionalInfoController.text.isEmpty) { + return false; + } + break; + default: + return false; + } + return true; } String getUserTitle() { @@ -446,12 +487,18 @@ class _ClaimStatementWindowState extends State { _icd10CodeController.dispose(); _preauthNoController.dispose(); _searchFocusNode.dispose(); + serviceDesc.dispose(); + medAid.dispose(); super.dispose(); } @override void initState() { + super.initState(); + + _serviceDescController.text = "Consultation"; _serviceDescController.addListener(serviceDescriptionSelected); + serviceDesc.value = "Consultation"; _medAidController.addListener(hasMedAid); _fullNameController.text = "${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}"; @@ -466,7 +513,7 @@ class _ClaimStatementWindowState extends State { "${getUserTitle()} ${widget.signedInUser.fname} ${widget.signedInUser.lname}"; _practiceNoController.text = widget.business!.practice_no; _vatNoController.text = widget.business!.vat_no; - super.initState(); + hasMedAid(); } @override From 68bbfc33994edbd3a97c10f8e5471b64e9e0073a Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 11:30:44 +0200 Subject: [PATCH 19/41] add text form field to file upload --- .../package_tools/patient_documents.dart | 228 ++++++++---------- 1 file changed, 105 insertions(+), 123 deletions(-) diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart index 1d874e34..8ed0a6b3 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart @@ -2,14 +2,17 @@ import 'dart:convert'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_file_api.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/med_cert_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_file_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; @@ -60,6 +63,7 @@ class _PatientDocumentsState extends State { final noRepeatsController = TextEditingController(); final outputController = TextEditingController(); late PlatformFile? selected; + final _formKey = GlobalKey(); late String env; Future submitDocUploadForm() async { @@ -217,7 +221,7 @@ class _PatientDocumentsState extends State { } } - void uploudFilePopUp() { + void uploudFilePopUp(double width) { showDialog( context: context, barrierDismissible: false, @@ -227,59 +231,100 @@ class _PatientDocumentsState extends State { onWindowTapClose: () { Navigator.pop(context); }, - windowBody: Column( - children: [ - MIHFileField( - controller: selectedFileController, - hintText: "Select File", - editable: false, - required: true, - onPressed: () async { - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: ['jpg', 'png', 'pdf'], - withData: true, - ); - if (result == null) return; - final selectedFile = result.files.first; - print("Selected file: $selectedFile"); - setState(() { - selected = selectedFile; - }); - setState(() { - selectedFileController.text = selectedFile.name; - }); - }, - ), - const SizedBox(height: 15), - MihButton( - onPressed: () { - if (isFileFieldsFilled()) { - submitDocUploadForm(); - // uploadSelectedFile(selected); - Navigator.pop(context); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: selectedFileController, + hintText: "Selected File", + requiredText: true, + readOnly: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + ), + const SizedBox(width: 10), + MihButton( + onPressed: () async { + FilePickerResult? result = + await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['jpg', 'png', 'pdf'], + withData: true, + ); + if (result == null) return; + final selectedFile = result.files.first; + print("Selected file: $selectedFile"); + setState(() { + selected = selectedFile; + }); + setState(() { + selectedFileController.text = selectedFile.name; + }); + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + child: Text( + "Attach", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 15), + MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitDocUploadForm(); + // uploadSelectedFile(selected); + Navigator.pop(context); + } else { + MihAlertServices().formNotFilledCompletely(context); + } }, - ); - } - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Add File", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + buttonColor: + MzanziInnovationHub.of(context)!.theme.successColor(), + width: 300, + child: Text( + "Add File", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], ), - ), - ], + ], + ), ), ), ); @@ -391,7 +436,7 @@ class _PatientDocumentsState extends State { } } - Widget getMenu() { + Widget getMenu(double width) { if (widget.type == "personal") { return Positioned( right: 10, @@ -415,7 +460,7 @@ class _PatientDocumentsState extends State { backgroundColor: MzanziInnovationHub.of(context)!.theme.successColor(), onTap: () { - uploudFilePopUp(); + uploudFilePopUp(width); }, ) ], @@ -444,7 +489,7 @@ class _PatientDocumentsState extends State { backgroundColor: MzanziInnovationHub.of(context)!.theme.successColor(), onTap: () { - uploudFilePopUp(); + uploudFilePopUp(width); }, ), SpeedDialChild( @@ -489,70 +534,6 @@ class _PatientDocumentsState extends State { } } - List setIcons() { - if (widget.type == "personal") { - return [ - Text( - "Documents", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - IconButton( - onPressed: () { - uploudFilePopUp(); - }, - icon: Icon( - Icons.add, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ) - ]; - } else { - return [ - Text( - "Documents", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - IconButton( - onPressed: () { - medCertPopUp(); - }, - icon: Icon( - Icons.sick_outlined, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - IconButton( - onPressed: () { - prescritionPopUp(); - }, - icon: Icon( - Icons.medication_outlined, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - IconButton( - onPressed: () { - uploudFilePopUp(); - }, - icon: Icon( - Icons.add, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ) - ]; - } - } - void successPopUp(String message) { showDialog( context: context, @@ -603,13 +584,14 @@ class _PatientDocumentsState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MihPackageToolBody( borderOn: false, - bodyItem: getBody(), + bodyItem: getBody(screenWidth), ); } - Widget getBody() { + Widget getBody(double width) { return Stack( children: [ MihSingleChildScroll( @@ -641,7 +623,7 @@ class _PatientDocumentsState extends State { }, ), ), - getMenu(), + getMenu(width), ], ); } From 67a84d52d902c601e0958668714669104555522d Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 11:37:13 +0200 Subject: [PATCH 20/41] button alignment --- .../build_mih_patient_search_list.dart | 218 ++++++++++-------- .../package_tools/mih_patient_search.dart | 2 - 2 files changed, 119 insertions(+), 101 deletions(-) diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_mih_patient_search_list.dart b/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_mih_patient_search_list.dart index ad385451..8486024e 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_mih_patient_search_list.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_mih_patient_search_list.dart @@ -280,7 +280,7 @@ class _BuildPatientsListState extends State { visible: !hasAccess, child: Column( mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Important Notice: Requesting Patient Profile Access", @@ -343,111 +343,131 @@ class _BuildPatientsListState extends State { ), ), // const SizedBox(height: 15.0), - Wrap(runSpacing: 10, spacing: 10, children: [ - Visibility( - visible: hasAccess, - child: MihButton( - onPressed: () { - if (hasAccess) { - Navigator.of(context) - .pushNamed('/patient-manager/patient', - arguments: PatientViewArguments( - widget.signedInUser, - widget.patients[index], - widget.businessUser, - widget.business, - "business", - )); - } else { - noAccessWarning(); - } - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.successColor(), - width: 300, - child: Text( - "View Profile", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - Visibility( - visible: !hasAccess && accessStatus == "No Access", - child: MihButton( - onPressed: () { - MIHApiCalls.addPatientAccessAPICall( - widget.business!.business_id, - widget.patients[index].app_id, - "patient", - widget.business!.Name, - widget.personalSelected, - BusinessArguments( - widget.signedInUser, - widget.businessUser, - widget.business, + Center( + child: Wrap( + alignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + runSpacing: 10, + spacing: 10, + children: [ + Visibility( + visible: hasAccess, + child: Center( + child: MihButton( + onPressed: () { + if (hasAccess) { + Navigator.of(context) + .pushNamed('/patient-manager/patient', + arguments: PatientViewArguments( + widget.signedInUser, + widget.patients[index], + widget.businessUser, + widget.business, + "business", + )); + } else { + noAccessWarning(); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .successColor(), + width: 300, + child: Text( + "View Profile", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), ), - context, - ); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.successColor(), - width: 300, - child: Text( - "Request Access", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, ), ), - ), - ), - Visibility( - visible: !hasAccess && accessStatus == "declined", - child: MihButton( - onPressed: () { - MIHApiCalls.reapplyPatientAccessAPICall( - widget.business!.business_id, - widget.patients[index].app_id, - widget.personalSelected, - BusinessArguments( - widget.signedInUser, - widget.businessUser, - widget.business, + Visibility( + visible: !hasAccess && accessStatus == "No Access", + child: Center( + child: MihButton( + onPressed: () { + MIHApiCalls.addPatientAccessAPICall( + widget.business!.business_id, + widget.patients[index].app_id, + "patient", + widget.business!.Name, + widget.personalSelected, + BusinessArguments( + widget.signedInUser, + widget.businessUser, + widget.business, + ), + context, + ); + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .successColor(), + width: 300, + child: Text( + "Request Access", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), ), - context, - ); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Re-apply", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, ), ), - ), + Visibility( + visible: !hasAccess && accessStatus == "declined", + child: Center( + child: MihButton( + onPressed: () { + MIHApiCalls.reapplyPatientAccessAPICall( + widget.business!.business_id, + widget.patients[index].app_id, + widget.personalSelected, + BusinessArguments( + widget.signedInUser, + widget.businessUser, + widget.business, + ), + context, + ); + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 300, + child: Text( + "Re-apply", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ), + Visibility( + visible: !hasAccess && accessStatus == "pending", + child: const SizedBox( + width: 500, + //height: 50, + child: Text( + "Patient has not approved access to their profile. Once access has been approved you can book and appointment or view their profile."), + ), + ), + ], ), - Visibility( - visible: !hasAccess && accessStatus == "pending", - child: const SizedBox( - width: 500, - //height: 50, - child: Text( - "Patient has not approved access to their profile. Once access has been approved you can book and appointment or view their profile."), - ), - ), - ]) + ), ], ), ), diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart b/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart index e96716ec..01a77c35 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart @@ -12,7 +12,6 @@ import 'package:mzansi_innovation_hub/mih_objects/patient_access.dart'; import 'package:mzansi_innovation_hub/mih_objects/patients.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/list_builders/build_mih_patient_search_list.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; class MihPatientSearch extends StatefulWidget { final AppUser signedInUser; @@ -188,7 +187,6 @@ class _MihPatientSearchState extends State { @override void dispose() { - // TODO: implement dispose super.dispose(); _searchFocusNode.dispose(); _mihPatientSearchController.dispose(); From fa406431bd443ffc558818ddb6e88c03f06a9f08 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 12:05:14 +0200 Subject: [PATCH 21/41] use new input in settings --- .../mzansi_ai/package_tools/ai_chat.dart | 172 +++++++++++------- 1 file changed, 104 insertions(+), 68 deletions(-) diff --git a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart index a2bde0d0..8d070e00 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart @@ -4,10 +4,11 @@ import 'dart:convert'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_numeric_stepper.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_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_radio_options.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; @@ -370,26 +371,30 @@ class _AiChatState extends State { ), ], ), - const SizedBox(height: 5), + const SizedBox(height: 15), Row( - mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( width: 300, - child: MIHDropdownField( + child: MihRadioOptions( controller: _modelController, hintText: "AI Model", - dropdownOptions: const [ + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + requiredText: true, + radioOptions: const [ 'gemma3:4b', ], - required: true, - editable: true, - enableSearch: false, ), ), ], ), - const SizedBox(height: 15), + const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.start, children: [ @@ -433,49 +438,24 @@ class _AiChatState extends State { ), ], ), - const SizedBox(height: 15), + const SizedBox(height: 10), Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, children: [ - IconButton.filled( - onPressed: () { - setState(() { - _chatFrontSize -= 1; - _fontSizeController.text = - _chatFrontSize.ceil().toString(); - }); - }, - icon: const Icon( - Icons.remove, - ), - ), - const SizedBox(width: 10), - MihTextFormField( - width: 200, - fillColor: MzanziInnovationHub.of(context)! - .theme - .secondaryColor(), - inputColor: MzanziInnovationHub.of(context)! - .theme - .primaryColor(), - controller: _fontSizeController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Time", - ), - const SizedBox(width: 10), - IconButton.filled( - onPressed: () { - setState(() { - _chatFrontSize += 1; - _fontSizeController.text = - _chatFrontSize.ceil().toString(); - }); - }, - icon: const Icon( - Icons.add, + SizedBox( + width: 300, + child: MihNumericStepper( + controller: _fontSizeController, + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + hintText: "Font Size", + requiredText: true, + minValue: 1, + // maxValue: 5, + validationOn: true, ), ), ], @@ -537,6 +517,12 @@ class _AiChatState extends State { } } + void fontSizeChanged() { + setState(() { + _chatFrontSize = double.parse(_fontSizeController.text); + }); + } + @override void dispose() { // TODO: implement dispose @@ -545,12 +531,14 @@ class _AiChatState extends State { _fontSizeController.dispose(); _ttsVoiceController.dispose(); _ttsVoiceController.removeListener(voiceSelected); + _fontSizeController.removeListener(fontSizeChanged); client.endSession(); _flutterTts.stop(); } void initTTS() { - _flutterTts.setVolume(0.7); + _flutterTts.setVolume(1); + _fontSizeController.addListener(fontSizeChanged); // _flutterTts.setSpeechRate(0.6); // _flutterTts.setPitch(1.0); _flutterTts.getVoices.then( @@ -650,27 +638,75 @@ class _AiChatState extends State { ], ), Positioned( - left: 0, - top: 0, + left: 15, + top: 15, child: Visibility( visible: _showModelOptions.value == true, - child: IconButton.filled( - iconSize: 20, - onPressed: () { - if (_showModelOptions.value == true) { - setState(() { - _showModelOptions.value = false; - }); - } else { - setState(() { - _showModelOptions.value = true; - }); - } - }, - icon: const Icon( - Icons.settings, + child: 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), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.only( + top: 2.0, + left: 5.0, + ), + child: SizedBox( + width: 40, + child: IconButton.filled( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all( + MzanziInnovationHub.of(context)!.theme.errorColor()), + ), + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + iconSize: 20, + onPressed: () { + if (_showModelOptions.value == true) { + setState(() { + _showModelOptions.value = false; + }); + } else { + setState(() { + _showModelOptions.value = true; + }); + } + }, + icon: const Icon( + Icons.close, + ), + ), + ), ), ), + // IconButton.filled( + // iconSize: 20, + // onPressed: () { + // if (_showModelOptions.value == true) { + // setState(() { + // _showModelOptions.value = false; + // }); + // } else { + // setState(() { + // _showModelOptions.value = true; + // }); + // } + // }, + // icon: const Icon( + // Icons.settings, + // ), + // ), ), ), Positioned( From bc004675e2f9f8462535ab03e12ddbb938ccaf07 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 12:07:41 +0200 Subject: [PATCH 22/41] remove comments --- .../authentication/reset_password.dart | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/Frontend/lib/mih_packages/authentication/reset_password.dart b/Frontend/lib/mih_packages/authentication/reset_password.dart index a4ed515b..2df21e28 100644 --- a/Frontend/lib/mih_packages/authentication/reset_password.dart +++ b/Frontend/lib/mih_packages/authentication/reset_password.dart @@ -275,29 +275,6 @@ class _ResetPasswordState extends State { }, ), - // //email input - // SizedBox( - // width: 500.0, - // child: MIHPassField( - // controller: passwordController, - // hintText: 'New Password', - // required: true, - // signIn: false, - // ), - // ), - // //spacer - // const SizedBox(height: 10), - // //password input - // SizedBox( - // width: 500.0, - // child: MIHPassField( - // controller: confirmPasswordController, - // hintText: 'Confirm New Password', - // required: true, - // signIn: false, - // ), - // ), - //spacer const SizedBox(height: 25), // sign in button From 65c9679806ae873673d5245db464c80dbd22feaf Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 12:08:44 +0200 Subject: [PATCH 23/41] delete legacy inputs --- .../mih_file_input.dart | 177 --------------- .../mih_multiline_text_input.dart | 146 ------------- .../mih_number_input.dart | 203 ------------------ .../mih_pass_input.dart | 194 ----------------- .../mih_text_input.dart | 187 ---------------- 5 files changed, 907 deletions(-) delete mode 100644 Frontend/lib/mih_components/mih_inputs_and_buttons/mih_file_input.dart delete mode 100644 Frontend/lib/mih_components/mih_inputs_and_buttons/mih_multiline_text_input.dart delete mode 100644 Frontend/lib/mih_components/mih_inputs_and_buttons/mih_number_input.dart delete mode 100644 Frontend/lib/mih_components/mih_inputs_and_buttons/mih_pass_input.dart delete mode 100644 Frontend/lib/mih_components/mih_inputs_and_buttons/mih_text_input.dart diff --git a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_file_input.dart b/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_file_input.dart deleted file mode 100644 index 8cc102c5..00000000 --- a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_file_input.dart +++ /dev/null @@ -1,177 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../main.dart'; - -class MIHFileField extends StatefulWidget { - final TextEditingController controller; - final String hintText; - final bool editable; - final bool required; - final void Function() onPressed; - - const MIHFileField({ - super.key, - required this.controller, - required this.hintText, - required this.editable, - required this.required, - required this.onPressed, - }); - - @override - State createState() => _MIHFileFieldState(); -} - -class _MIHFileFieldState extends State { - bool startup = true; - final FocusNode _focus = FocusNode(); - - bool makeEditable() { - if (widget.editable) { - return false; - } else { - return true; - } - } - - String? get _errorText { - final text = widget.controller.text; - String errorMessage = ''; - if (startup) { - return null; - } - if (!widget.required) { - return null; - } - if (text.isEmpty) { - return "${widget.hintText} is required"; - } - if (widget.hintText == "Email" && !isEmailValid(text)) { - errorMessage += "Enter a valid email address\n"; - } - if (widget.hintText == "Username" && text.length < 8) { - errorMessage += "• Username must contain at least 8 characters.\n"; - } - if (widget.hintText == "Username" && !isUsernameValid(text)) { - errorMessage += "• Username can only contain '_' special Chracters.\n"; - } - if (errorMessage.isEmpty) { - return null; - } - // If there are no error messages, the password is valid - return errorMessage; - } - - bool isUsernameValid(String username) { - return RegExp(r'^(?=[a-zA-Z0-9._]{8,20}$)(?!.*[_.]{2})[^_.].*[^_.]$') - .hasMatch(username); - } - - bool isEmailValid(String email) { - return RegExp(r'^[\w-\.]+@[a-zA-Z]+\.[a-zA-Z]{2,}$').hasMatch(email); - } - - void _onFocusChange() { - setState(() { - startup = false; - }); - } - - Widget setRequiredText() { - if (widget.required) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "*", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor()), - ), - const SizedBox( - width: 8.0, - ), - Text(widget.hintText, - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor())), - ], - ); - } else { - return Text(widget.hintText, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor())); - } - } - - @override - void dispose() { - _focus.dispose(); - super.dispose(); - } - - @override - void initState() { - _focus.addListener(_onFocusChange); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return TextField( - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - controller: widget.controller, - focusNode: _focus, - readOnly: makeEditable(), - //enabled: !makeEditable(), - obscureText: false, - onChanged: (_) => setState(() { - startup = false; - }), - decoration: InputDecoration( - suffixIcon: IconButton( - icon: const Icon(Icons.attach_file), - onPressed: widget.onPressed, - ), - label: setRequiredText(), - //labelStyle: TextStyle(color: MzanziInnovationHub.of(context)!.theme.primaryColor()), - fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - filled: true, - errorText: _errorText, - errorStyle: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - fontWeight: FontWeight.bold), - //errorBorder: const InputBorder(), - //hintText: hintText, - //hintStyle: TextStyle(color: Colors.blueGrey[400]), - disabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ), - ), - ); - } -} diff --git a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_multiline_text_input.dart b/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_multiline_text_input.dart deleted file mode 100644 index 7a33a483..00000000 --- a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_multiline_text_input.dart +++ /dev/null @@ -1,146 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../main.dart'; - -class MIHMLTextField extends StatefulWidget { - final TextEditingController controller; - final String hintText; - final bool editable; - final bool required; - - const MIHMLTextField({ - super.key, - required this.controller, - required this.hintText, - required this.editable, - required this.required, - }); - - @override - State createState() => _MIHMLTextFieldState(); -} - -class _MIHMLTextFieldState extends State { - bool startup = true; - final FocusNode _focus = FocusNode(); - - bool makeEditable() { - if (widget.editable) { - return false; - } else { - return true; - } - } - - String? get _errorText { - final text = widget.controller.text; - if (startup) { - return null; - } - if (!widget.required) { - return null; - } - if (text.isEmpty) { - return "${widget.hintText} is required"; - } - return null; - } - - void _onFocusChange() { - setState(() { - startup = false; - }); - } - - Widget setRequiredText() { - if (widget.required) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "*", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor()), - ), - const SizedBox( - width: 8.0, - ), - Text(widget.hintText, - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor())), - ], - ); - } else { - return Text(widget.hintText, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor())); - } - } - - @override - void dispose() { - _focus.dispose(); - super.dispose(); - } - - @override - void initState() { - _focus.addListener(_onFocusChange); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return TextField( - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - textAlign: TextAlign.start, - textAlignVertical: TextAlignVertical.top, - expands: true, - maxLines: null, - controller: widget.controller, - readOnly: makeEditable(), - obscureText: false, - focusNode: _focus, - onChanged: (_) => setState(() { - startup = false; - }), - decoration: InputDecoration( - label: setRequiredText(), - errorText: _errorText, - errorStyle: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - fontWeight: FontWeight.bold), - labelStyle: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - alignLabelWithHint: true, - fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - filled: true, - //hintText: hintText, - //hintStyle: TextStyle(color: Colors.blueGrey[400]), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ), - ), - ); - } -} diff --git a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_number_input.dart b/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_number_input.dart deleted file mode 100644 index dee3e614..00000000 --- a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_number_input.dart +++ /dev/null @@ -1,203 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import '../../main.dart'; - -class MIHNumberField extends StatefulWidget { - final TextEditingController controller; - final String hintText; - final bool editable; - final bool required; - final bool enableDecimal; - final Iterable? autoFillHintGroup; - - const MIHNumberField({ - super.key, - required this.controller, - required this.hintText, - required this.editable, - required this.required, - required this.enableDecimal, - this.autoFillHintGroup, - }); - - @override - State createState() => _MIHNumberFieldState(); -} - -class _MIHNumberFieldState extends State { - bool startup = true; - final FocusNode _focus = FocusNode(); - - List allowDecimals() { - if (widget.enableDecimal) { - return [ - FilteringTextInputFormatter.allow(RegExp(r'^\d+(\.\d*)?')), - ]; - } else { - return [FilteringTextInputFormatter.digitsOnly]; - } - } - - bool makeEditable() { - if (widget.editable) { - return false; - } else { - return true; - } - } - - String? get _errorText { - final text = widget.controller.text; - String errorMessage = ''; - if (startup) { - return null; - } - if (!widget.required) { - return null; - } - if (text.isEmpty) { - return "${widget.hintText} is required"; - } - if (widget.hintText == "Email" && !isEmailValid(text)) { - errorMessage += "Enter a valid email address\n"; - } - // if (widget.hintText == "Username" && text.length < 8) { - // errorMessage += "• Username must contain at least 8 characters.\n"; - // } - if (widget.hintText == "Username" && !isUsernameValid(text)) { - errorMessage += "Let's create a great username for you!\n"; - errorMessage += "• Your username should start with a letter.\n"; - errorMessage += "• You can use letters, numbers, and/ or underscores.\n"; - errorMessage += "• Keep it between 6 and 30 characters.\n"; - errorMessage += "• Avoid special characters like @, #, or \$.\"\n"; - } - if (errorMessage.isEmpty) { - return null; - } - // If there are no error messages, the password is valid - return errorMessage; - } - - bool isUsernameValid(String username) { - return RegExp(r'^[a-zA-Z][a-zA-Z0-9_]{5,19}$').hasMatch(username); - } - - bool isEmailValid(String email) { - var regex = RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'); - return regex.hasMatch(email); - } - - void _onFocusChange() { - setState(() { - startup = false; - }); - } - - // List getAutoFillDetails(){ - // if(widget.autoFillHintGroup == null){ - // return []; - // } - // else{ - // return widget.autoFillHintGroup!; - // } - // } - - Widget setRequiredText() { - if (widget.required) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "*", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor()), - ), - const SizedBox( - width: 8.0, - ), - Text(widget.hintText, - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor())), - ], - ); - } else { - return Text(widget.hintText, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor())); - } - } - - @override - void dispose() { - _focus.dispose(); - super.dispose(); - } - - @override - void initState() { - _focus.addListener(_onFocusChange); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return TextField( - keyboardType: TextInputType.number, - inputFormatters: allowDecimals(), - autofillHints: widget.autoFillHintGroup, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - controller: widget.controller, - focusNode: _focus, - readOnly: makeEditable(), - //enabled: !makeEditable(), - obscureText: false, - onChanged: (_) => setState(() { - startup = false; - }), - decoration: InputDecoration( - label: setRequiredText(), - //labelStyle: TextStyle(color: MzanziInnovationHub.of(context)!.theme.primaryColor()), - fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - filled: true, - errorText: _errorText, - errorStyle: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - fontWeight: FontWeight.bold), - //errorBorder: const InputBorder(), - //hintText: hintText, - //hintStyle: TextStyle(color: Colors.blueGrey[400]), - disabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ), - ), - ); - } -} diff --git a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_pass_input.dart b/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_pass_input.dart deleted file mode 100644 index 73925004..00000000 --- a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_pass_input.dart +++ /dev/null @@ -1,194 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../main.dart'; - -class MIHPassField extends StatefulWidget { - final TextEditingController controller; - final String hintText; - final bool required; - final bool signIn; - final Iterable? autoFillHintGroup; - final TextInputAction? textInputAction; - - const MIHPassField({ - super.key, - required this.controller, - required this.hintText, - required this.required, - required this.signIn, - this.autoFillHintGroup, - this.textInputAction, - }); - - @override - State createState() => _MIHPassFieldState(); -} - -class _MIHPassFieldState extends State { - bool startup = true; - final textFieldFocusNode = FocusNode(); - bool _obscured = true; - //bool valid = false; - - void _toggleObscured() { - setState(() { - _obscured = !_obscured; - if (textFieldFocusNode.hasPrimaryFocus) { - return; // If focus is on text field, dont unfocus - } - textFieldFocusNode.canRequestFocus = - false; // Prevents focus if tap on eye - }); - } - - String? get _errorText { - final text = widget.controller.text; - String errorMessage = ''; - if (startup) { - return null; - } - if (!widget.required) { - return null; - } - if (text.isEmpty) { - return "${widget.hintText} is required"; - } - // Password length greater than 8 - if (text.length <= 8 && !widget.signIn) { - errorMessage += '• Password must contain at least 8 characters.\n'; - } - - // Contains at least one uppercase letter - if (!text.contains(RegExp(r'[A-Z]')) && !widget.signIn) { - errorMessage += '• Uppercase letter is missing.\n'; - } - - // Contains at least one lowercase letter - if (!text.contains(RegExp(r'[a-z]')) && !widget.signIn) { - errorMessage += '• Lowercase letter is missing.\n'; - } - - // Contains at least one digit - if (!text.contains(RegExp(r'[0-9]')) && !widget.signIn) { - errorMessage += '• number is missing.\n'; - } - - // Contains at least one special character - if (!text.contains(RegExp(r'[!@#$%^&*]')) && !widget.signIn) { - errorMessage += '• Special character is missing - !@#\$%^&*\n'; - } - - // Contains no errors - if (errorMessage.isEmpty) { - return null; - } - // If there are no error messages, the password is valid - return errorMessage; - } - - Widget setRequiredText() { - if (widget.required) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "*", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor()), - ), - const SizedBox( - width: 8.0, - ), - Text(widget.hintText, - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor())), - ], - ); - } else { - return Text(widget.hintText, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor())); - } - } - - void _onFocusChange() { - setState(() { - startup = false; - }); - } - - @override - void dispose() { - textFieldFocusNode.dispose(); - super.dispose(); - } - - @override - void initState() { - textFieldFocusNode.addListener(_onFocusChange); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return TextField( - autofillHints: widget.autoFillHintGroup, - textInputAction: widget.textInputAction, - controller: widget.controller, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - obscureText: _obscured, - focusNode: textFieldFocusNode, - onChanged: (_) => setState(() { - startup = false; - }), - decoration: InputDecoration( - fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - filled: true, - label: setRequiredText(), - //labelStyle: const TextStyle(color: Colors.blueAccent), - errorText: _errorText, - errorStyle: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - fontWeight: FontWeight.bold), - //hintText: widget.hintText, - //hintStyle: TextStyle(color: Colors.blueGrey[400]), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ), - suffixIcon: Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 4, 0), - child: GestureDetector( - onTap: _toggleObscured, - child: Icon( - _obscured - ? Icons.visibility_rounded - : Icons.visibility_off_rounded, - size: 24, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - ), - ), - ); - } -} diff --git a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_text_input.dart b/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_text_input.dart deleted file mode 100644 index 301b8ce7..00000000 --- a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_text_input.dart +++ /dev/null @@ -1,187 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../main.dart'; - -class MIHTextField extends StatefulWidget { - final TextEditingController controller; - final String hintText; - final bool editable; - final bool required; - final TextInputAction? textInputAction; - final Iterable? autoFillHintGroup; - - const MIHTextField({ - super.key, - required this.controller, - required this.hintText, - required this.editable, - required this.required, - this.autoFillHintGroup, - this.textInputAction, - }); - - @override - State createState() => _MIHTextFieldState(); -} - -class _MIHTextFieldState extends State { - bool startup = true; - final FocusNode _focus = FocusNode(); - - bool makeEditable() { - if (widget.editable) { - return false; - } else { - return true; - } - } - - String? get _errorText { - final text = widget.controller.text; - String errorMessage = ''; - if (startup) { - return null; - } - if (!widget.required) { - return null; - } - if (text.isEmpty) { - return "${widget.hintText} is required"; - } - if (widget.hintText == "Email" && !isEmailValid(text)) { - errorMessage += "Enter a valid email address\n"; - } - // if (widget.hintText == "Username" && text.length < 8) { - // errorMessage += "• Username must contain at least 8 characters.\n"; - // } - if (widget.hintText == "Username" && !isUsernameValid(text)) { - errorMessage += "Let's create a great username for you!\n"; - errorMessage += "• Your username should start with a letter.\n"; - errorMessage += "• You can use letters, numbers, and/ or underscores.\n"; - errorMessage += "• Keep it between 6 and 30 characters.\n"; - errorMessage += "• Avoid special characters like @, #, or \$.\"\n"; - } - if (errorMessage.isEmpty) { - return null; - } - // If there are no error messages, the password is valid - return errorMessage; - } - - bool isUsernameValid(String username) { - return RegExp(r'^[a-zA-Z][a-zA-Z0-9_]{5,19}$').hasMatch(username); - } - - bool isEmailValid(String email) { - var regex = RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'); - return regex.hasMatch(email); - } - - void _onFocusChange() { - setState(() { - startup = false; - }); - } - - // List getAutoFillDetails(){ - // if(widget.autoFillHintGroup == null){ - // return []; - // } - // else{ - // return widget.autoFillHintGroup!; - // } - // } - - Widget setRequiredText() { - if (widget.required) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "*", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor()), - ), - const SizedBox( - width: 8.0, - ), - Text(widget.hintText, - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor())), - ], - ); - } else { - return Text(widget.hintText, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor())); - } - } - - @override - void dispose() { - _focus.dispose(); - super.dispose(); - } - - @override - void initState() { - _focus.addListener(_onFocusChange); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return TextField( - autofillHints: widget.autoFillHintGroup, - textInputAction: widget.textInputAction, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - controller: widget.controller, - focusNode: _focus, - readOnly: makeEditable(), - //enabled: !makeEditable(), - obscureText: false, - onChanged: (_) => setState(() { - startup = false; - }), - decoration: InputDecoration( - label: setRequiredText(), - fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - filled: true, - errorText: _errorText, - errorStyle: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - fontWeight: FontWeight.bold), - disabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ), - ), - ); - } -} From f2a4ba66ebf3612a0c988aa020b2b0d51b9a6713 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 12:36:06 +0200 Subject: [PATCH 24/41] new date and time fields --- .../mih_date_field.dart | 180 +++++++++++++++++ .../mih_time_field.dart | 190 ++++++++++++++++++ 2 files changed, 370 insertions(+) create mode 100644 Frontend/lib/mih_components/mih_package_components/mih_date_field.dart create mode 100644 Frontend/lib/mih_components/mih_package_components/mih_time_field.dart diff --git a/Frontend/lib/mih_components/mih_package_components/mih_date_field.dart b/Frontend/lib/mih_components/mih_package_components/mih_date_field.dart new file mode 100644 index 00000000..e89b4608 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_date_field.dart @@ -0,0 +1,180 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/main.dart'; + +class MihDateField extends StatefulWidget { + final TextEditingController controller; + final String labelText; + final bool required; + final double? width; + final double? height; + final double? borderRadius; + final double? elevation; + final FormFieldValidator? validator; + const MihDateField({ + super.key, + required this.controller, + required this.labelText, + required this.required, + this.width, + this.height, + this.borderRadius, + this.elevation, + this.validator, + }); + + @override + State createState() => _MihDateFieldState(); +} + +class _MihDateFieldState extends State { + FormFieldState? _formFieldState; + + Future _selectDate(BuildContext context) async { + DateTime? picked = await showDatePicker( + context: context, + initialDate: widget.controller.text.isNotEmpty + ? DateTime.tryParse(widget.controller.text) ?? DateTime.now() + : DateTime.now(), + firstDate: DateTime(2000), + lastDate: DateTime(2100), + ); + if (picked != null) { + widget.controller.text = picked.toString().split(" ")[0]; + _formFieldState?.didChange(widget.controller.text); + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + final theme = MzanziInnovationHub.of(context)!.theme; + return Center( + child: SizedBox( + width: widget.width, + height: widget.height, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.labelText, + style: TextStyle( + color: theme.secondaryColor(), + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + if (!widget.required) + Text( + "(Optional)", + style: TextStyle( + color: theme.secondaryColor(), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 4), + FormField( + initialValue: widget.controller.text, + validator: widget.validator, + autovalidateMode: AutovalidateMode.onUserInteraction, + builder: (field) { + _formFieldState = field; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Material( + elevation: widget.elevation ?? 4.0, + borderRadius: + BorderRadius.circular(widget.borderRadius ?? 8.0), + child: TextFormField( + controller: widget.controller, + readOnly: true, + onTap: () => _selectDate(context), + style: TextStyle( + color: theme.primaryColor(), + fontWeight: FontWeight.w500, + ), + decoration: InputDecoration( + suffixIcon: Icon( + Icons.calendar_today, + color: theme.primaryColor(), + ), + errorStyle: const TextStyle(height: 0, fontSize: 0), + contentPadding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 8.0), + filled: true, + fillColor: theme.secondaryColor(), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: field.hasError + ? BorderSide( + color: theme.errorColor(), + width: 2.0, + ) + : BorderSide.none, + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: BorderSide.none, + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: BorderSide( + color: field.hasError + ? theme.errorColor() + : theme.secondaryColor(), + width: 3.0, + ), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: BorderSide( + color: theme.errorColor(), + width: 3.0, + ), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: BorderSide( + color: theme.errorColor(), + width: 3.0, + ), + ), + ), + onChanged: (value) { + field.didChange(value); + }, + ), + ), + if (field.hasError) + Padding( + padding: const EdgeInsets.only(left: 8.0, top: 4.0), + child: Text( + field.errorText ?? '', + style: TextStyle( + fontSize: 12, + color: theme.errorColor(), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ); + }, + ), + ], + ), + ), + ); + } +} diff --git a/Frontend/lib/mih_components/mih_package_components/mih_time_field.dart b/Frontend/lib/mih_components/mih_package_components/mih_time_field.dart new file mode 100644 index 00000000..89ddc0ca --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_time_field.dart @@ -0,0 +1,190 @@ +import 'package:flutter/material.dart'; +import '../../main.dart'; + +class MihTimeField extends StatefulWidget { + final TextEditingController controller; + final String labelText; + final bool required; + final double? width; + final double? height; + final double? borderRadius; + final double? elevation; + final FormFieldValidator? validator; + + const MihTimeField({ + super.key, + required this.controller, + required this.labelText, + required this.required, + this.width, + this.height, + this.borderRadius, + this.elevation, + this.validator, + }); + + @override + State createState() => _MihTimeFieldState(); +} + +class _MihTimeFieldState extends State { + FormFieldState? _formFieldState; + + Future _selectTime(BuildContext context) async { + TimeOfDay? picked = await showTimePicker( + context: context, + initialTime: widget.controller.text.isNotEmpty + ? TimeOfDay( + hour: int.tryParse(widget.controller.text.split(":")[0]) ?? 0, + minute: int.tryParse(widget.controller.text.split(":")[1]) ?? 0, + ) + : TimeOfDay.now(), + builder: (context, child) { + return MediaQuery( + data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true), + child: child as Widget, + ); + }, + ); + if (picked != null) { + final hours = picked.hour.toString().padLeft(2, '0'); + final minutes = picked.minute.toString().padLeft(2, '0'); + widget.controller.text = "$hours:$minutes"; + _formFieldState?.didChange(widget.controller.text); + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + final theme = MzanziInnovationHub.of(context)!.theme; + return Center( + child: SizedBox( + width: widget.width, + height: widget.height, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.labelText, + style: TextStyle( + color: theme.secondaryColor(), + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + if (!widget.required) + Text( + "(Optional)", + style: TextStyle( + color: theme.secondaryColor(), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 4), + FormField( + initialValue: widget.controller.text, + validator: widget.validator, + autovalidateMode: AutovalidateMode.onUserInteraction, + builder: (field) { + _formFieldState = field; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Material( + elevation: widget.elevation ?? 4.0, + borderRadius: + BorderRadius.circular(widget.borderRadius ?? 8.0), + child: TextFormField( + controller: widget.controller, + readOnly: true, + onTap: () => _selectTime(context), + style: TextStyle( + color: theme.primaryColor(), + fontWeight: FontWeight.w500, + ), + decoration: InputDecoration( + suffixIcon: Icon( + Icons.access_time, + color: theme.primaryColor(), + ), + errorStyle: const TextStyle(height: 0, fontSize: 0), + contentPadding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 8.0), + filled: true, + fillColor: theme.secondaryColor(), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: field.hasError + ? BorderSide( + color: theme.errorColor(), + width: 2.0, + ) + : BorderSide.none, + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: BorderSide.none, + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: BorderSide( + color: field.hasError + ? theme.errorColor() + : theme.secondaryColor(), + width: 3.0, + ), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: BorderSide( + color: theme.errorColor(), + width: 3.0, + ), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: BorderSide( + color: theme.errorColor(), + width: 3.0, + ), + ), + ), + onChanged: (value) { + field.didChange(value); + }, + ), + ), + if (field.hasError) + Padding( + padding: const EdgeInsets.only(left: 8.0, top: 4.0), + child: Text( + field.errorText ?? '', + style: TextStyle( + fontSize: 12, + color: theme.errorColor(), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ); + }, + ), + ], + ), + ), + ); + } +} From 95d26a3f8be1961670cba0aafc96efe017879b75 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 12:38:30 +0200 Subject: [PATCH 25/41] use new date and time in example --- .../package_tools/package_tool_one.dart | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 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 d198072c..84229de1 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 @@ -6,6 +6,7 @@ import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_date_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_numeric_stepper.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; @@ -14,8 +15,10 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_image_display.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_radio_options.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_time_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; class PackageToolOne extends StatefulWidget { @@ -38,6 +41,9 @@ class _PackageToolOneState extends State { TextEditingController _textFieldThreeController = TextEditingController(); TextEditingController _textFieldFourController = TextEditingController(); TextEditingController _textFieldFiveController = TextEditingController(); + TextEditingController _textFieldSixController = TextEditingController(); + TextEditingController _textFieldSevenController = TextEditingController(); + TextEditingController _textFieldEightController = TextEditingController(); bool switchpositioin = true; final FocusNode searchFocusNode = FocusNode(); final _formKey = GlobalKey(); @@ -234,7 +240,7 @@ class _PackageToolOneState extends State { hintText: "Number Stepper", requiredText: true, minValue: 1, - // maxValue: 5, + maxValue: 5, validationOn: true, ), const SizedBox(height: 10), @@ -246,7 +252,7 @@ class _PackageToolOneState extends State { .secondaryColor(), secondaryFillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - readOnly: true, + readOnly: false, onChange: (value) { setState(() { switchpositioin = value; @@ -255,6 +261,36 @@ class _PackageToolOneState extends State { }, ), const SizedBox(height: 10), + MihRadioOptions( + controller: _textFieldSixController, + hintText: "Radio Options", + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + requiredText: true, + radioOptions: const ["Option 1", "Option 2"], + ), + const SizedBox(height: 10), + MihDateField( + controller: _textFieldSevenController, + labelText: "Date Field", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTimeField( + controller: _textFieldEightController, + labelText: "Time Field", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), MihTextFormField( height: 250, fillColor: MzanziInnovationHub.of(context)! From d8ac56d722ffe57be2b5cdbc607855bf8e4f247b Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 12:38:53 +0200 Subject: [PATCH 26/41] use new date and time in Calendar --- .../builder/build_appointment_list.dart | 32 +++++++++---------- .../calendar/package_tools/appointments.dart | 32 +++++++++---------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart b/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart index 8b1abed4..a47422bd 100644 --- a/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart +++ b/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart @@ -3,12 +3,12 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_mzansi_calendar_apis.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_date_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_time_input.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'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_time_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_delete_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; @@ -439,22 +439,22 @@ class _BuildAppointmentListState extends State { }, ), const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHDateField( - controller: widget.dateController, - lableText: "Date", - required: true, - ), + MihDateField( + controller: widget.dateController, + labelText: "Date", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTimeField( - controller: widget.timeController, - lableText: "Time", - required: true, - ), + MihTimeField( + controller: widget.timeController, + labelText: "Time", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 10), MihTextFormField( diff --git a/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart b/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart index f443d574..9a6450f9 100644 --- a/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart +++ b/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart @@ -2,15 +2,15 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_mzansi_calendar_apis.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_date_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_time_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_date_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_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_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_time_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_objects/appointment.dart'; import 'package:mzansi_innovation_hub/mih_objects/business.dart'; @@ -140,22 +140,22 @@ class _PatientAccessRequestState extends State { }, ), const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHDateField( - controller: _appointmentDateController, - lableText: "Date", - required: true, - ), + MihDateField( + controller: _appointmentDateController, + labelText: "Date", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTimeField( - controller: _appointmentTimeController, - lableText: "Time", - required: true, - ), + MihTimeField( + controller: _appointmentTimeController, + labelText: "Time", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 10), MihTextFormField( From c9a2f95a3fd19fc2f636149949f2cd6049d8ba8e Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 12:43:18 +0200 Subject: [PATCH 27/41] use new date and time in Pat Man --- .../build_my_patient_list_list.dart | 20 +++++--- .../package_tools/waiting_room.dart | 51 ++++++------------- 2 files changed, 29 insertions(+), 42 deletions(-) diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_my_patient_list_list.dart b/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_my_patient_list_list.dart index 273e31f0..e843e3fc 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_my_patient_list_list.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_my_patient_list_list.dart @@ -3,12 +3,12 @@ import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_api_calls.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_mzansi_calendar_apis.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_date_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_time_input.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'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_time_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_warning_message.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; @@ -152,16 +152,22 @@ class _BuildPatientsListState extends State { }, ), const SizedBox(height: 10.0), - MIHDateField( + MihDateField( controller: dateController, - lableText: "Date", + labelText: "Date", required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), - const SizedBox(height: 10.0), - MIHTimeField( + const SizedBox(height: 10), + MihTimeField( controller: timeController, - lableText: "Time", + labelText: "Time", required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 30.0), Center( diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart b/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart index bc5a283e..0d682bb6 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart @@ -4,15 +4,15 @@ import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_mzansi_calendar_apis.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_calendar.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_date_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_time_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_date_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_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_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_time_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; @@ -146,25 +146,6 @@ class _WaitingRoomState extends State { ], ), ), - // Positioned( - // right: 0, - // bottom: 0, - // child: Container( - // decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(50), - // color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - // ), - // child: IconButton( - // color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - // onPressed: () { - // appointmentTypeSelection(); - // }, - // icon: const Icon( - // Icons.add, - // size: 50, - // ), - // ), - // )) ], ); } @@ -340,22 +321,22 @@ class _WaitingRoomState extends State { }, ), const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHDateField( - controller: _appointmentDateController, - lableText: "Date", - required: true, - ), + MihDateField( + controller: _appointmentDateController, + labelText: "Date", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTimeField( - controller: _appointmentTimeController, - lableText: "Time", - required: true, - ), + MihTimeField( + controller: _appointmentTimeController, + labelText: "Time", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 10), MihTextFormField( From c88a2e93fbd974ce5a9eccc449d1a0f513905cf0 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 12:58:24 +0200 Subject: [PATCH 28/41] use new date and time in Doc Gen --- .../lib/mih_components/med_cert_input.dart | 62 ------- .../mih_date_input.dart | 152 ------------------ .../components/Claim_Statement_Window.dart | 14 +- .../package_tools/patient_documents.dart | 95 +++++++---- 4 files changed, 74 insertions(+), 249 deletions(-) delete mode 100644 Frontend/lib/mih_components/med_cert_input.dart delete mode 100644 Frontend/lib/mih_components/mih_inputs_and_buttons/mih_date_input.dart diff --git a/Frontend/lib/mih_components/med_cert_input.dart b/Frontend/lib/mih_components/med_cert_input.dart deleted file mode 100644 index 77c198f6..00000000 --- a/Frontend/lib/mih_components/med_cert_input.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:flutter/material.dart'; -import '../mih_components/mih_inputs_and_buttons/mih_date_input.dart'; - -class Medcertinput extends StatefulWidget { - final TextEditingController startDateController; - final TextEditingController endDateTextController; - final TextEditingController retDateTextController; - const Medcertinput({ - super.key, - required this.startDateController, - required this.endDateTextController, - required this.retDateTextController, - }); - - @override - State createState() => _MedcertinputState(); -} - -class _MedcertinputState extends State { - @override - void dispose() { - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return SizedBox( - //height: 325, - child: Column( - children: [ - //const SizedBox(height: 50.0), - SizedBox( - width: 700, - child: MIHDateField( - controller: widget.startDateController, - lableText: "From", - required: true, - ), - ), - const SizedBox(height: 10.0), - SizedBox( - width: 700, - child: MIHDateField( - controller: widget.endDateTextController, - lableText: "Up to Including", - required: true, - ), - ), - const SizedBox(height: 10.0), - SizedBox( - width: 700, - child: MIHDateField( - controller: widget.retDateTextController, - lableText: "Return", - required: true, - ), - ), - ], - ), - ); - } -} diff --git a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_date_input.dart b/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_date_input.dart deleted file mode 100644 index fd897383..00000000 --- a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_date_input.dart +++ /dev/null @@ -1,152 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../main.dart'; - -class MIHDateField extends StatefulWidget { - final TextEditingController controller; - final String lableText; - final bool required; - - const MIHDateField({ - super.key, - required this.controller, - required this.lableText, - required this.required, - }); - - @override - State createState() => _MIHDateFieldState(); -} - -class _MIHDateFieldState extends State { - final FocusNode _focus = FocusNode(); - bool startup = true; - // bool makeEditable() { - Future _selectDate(BuildContext context) async { - DateTime? picked = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(2000), - lastDate: DateTime(2100), - ); - if (picked != null) { - setState(() { - widget.controller.text = picked.toString().split(" ")[0]; - }); - } - } - - Widget setRequiredText() { - if (widget.required) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "*", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor()), - ), - const SizedBox( - width: 8.0, - ), - Text(widget.lableText, - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor())), - ], - ); - } else { - return Text(widget.lableText, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor())); - } - } - - void _onFocusChange() { - setState(() { - startup = false; - }); - } - - String? get _errorText { - final text = widget.controller.text; - if (startup) { - return null; - } - if (!widget.required) { - return null; - } - if (text.isEmpty) { - return "${widget.lableText} is required"; - } - return null; - } - - @override - void dispose() { - _focus.dispose(); - super.dispose(); - } - - @override - void initState() { - _focus.addListener(_onFocusChange); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return TextField( - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - controller: widget.controller, - readOnly: true, - obscureText: false, - focusNode: _focus, - onChanged: (_) => setState(() { - startup = false; - }), - decoration: InputDecoration( - errorText: _errorText, - errorStyle: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - fontWeight: FontWeight.bold), - label: setRequiredText(), - //labelText: widget.lableText, - //labelStyle: const TextStyle(color: Colors.blueAccent), - prefixIcon: Icon( - Icons.calendar_today, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - filled: true, - //hintText: hintText, - //hintStyle: TextStyle(color: Colors.blueGrey[400]), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ), - ), - onTap: () { - _selectDate(context); - }, - ); - } -} diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart index a3959a58..cb06b1e3 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart @@ -3,8 +3,8 @@ import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_claim_statement_generation_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_icd10_code_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_date_input.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'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_radio_options.dart'; @@ -118,11 +118,19 @@ class _ClaimStatementWindowState extends State { color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), const SizedBox(height: 10), - MIHDateField( + MihDateField( controller: _serviceDateController, - lableText: "Date of Service", + labelText: "Date of Service", required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), + // MIHDateField( + // controller: _serviceDateController, + // lableText: "Date of Service", + // required: true, + // ), const SizedBox(height: 10), MihRadioOptions( controller: _serviceDescController, diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart index 8ed0a6b3..ea894653 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart @@ -5,9 +5,9 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_file_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/med_cert_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_date_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; @@ -64,6 +64,7 @@ class _PatientDocumentsState extends State { final outputController = TextEditingController(); late PlatformFile? selected; final _formKey = GlobalKey(); + final _formKey2 = GlobalKey(); late String env; Future submitDocUploadForm() async { @@ -296,7 +297,7 @@ class _PatientDocumentsState extends State { ), ], ), - const SizedBox(height: 15), + const SizedBox(height: 20), MihButton( onPressed: () { if (_formKey.currentState!.validate()) { @@ -342,37 +343,67 @@ class _PatientDocumentsState extends State { }, windowBody: Column( children: [ - Medcertinput( - startDateController: startDateController, - endDateTextController: endDateTextController, - retDateTextController: retDateTextController, - ), - const SizedBox(height: 15.0), - MihButton( - onPressed: () async { - if (isMedCertFieldsFilled()) { - await generateMedCert(); - //Navigator.pop(context); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Generate", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + MihForm( + formKey: _formKey2, + formFields: [ + MihDateField( + controller: startDateController, + labelText: "From", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), - ), + const SizedBox(height: 10.0), + MihDateField( + controller: endDateTextController, + labelText: "Up to Including", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihDateField( + controller: retDateTextController, + labelText: "Return", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + // Medcertinput( + // startDateController: startDateController, + // endDateTextController: endDateTextController, + // retDateTextController: retDateTextController, + // ), + const SizedBox(height: 15.0), + Center( + child: MihButton( + onPressed: () async { + if (_formKey2.currentState!.validate()) { + await generateMedCert(); + //Navigator.pop(context); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + width: 300, + child: Text( + "Generate", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), ], ), From 67f8f20a8308ef9c27ab20c1ca1807765dbd2fa0 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 13:09:54 +0200 Subject: [PATCH 29/41] rename file --- Frontend/lib/mih_env/env.dart | 12 ++++++------ ...ment_Window.dart => claim_statement_window2.dart} | 5 ----- .../package_tools/patient_claim_or_statement.dart | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) rename Frontend/lib/mih_packages/patient_profile/pat_profile/components/{Claim_Statement_Window.dart => claim_statement_window2.dart} (99%) diff --git a/Frontend/lib/mih_env/env.dart b/Frontend/lib/mih_env/env.dart index 903bcfe5..842552b8 100644 --- a/Frontend/lib/mih_env/env.dart +++ b/Frontend/lib/mih_env/env.dart @@ -15,13 +15,13 @@ abstract class AppEnviroment { case Enviroment.dev: { //================= Android Dev Urls ================= - // baseApiUrl = "http://10.0.2.2:8080"; - // baseFileUrl = "http://10.0.2.2:9000"; - // baseAiUrl = "http://10.0.2.2:11434"; + baseApiUrl = "http://10.0.2.2:8080"; + baseFileUrl = "http://10.0.2.2:9000"; + baseAiUrl = "http://10.0.2.2:11434"; //================= Web Dev Urls ================= - baseApiUrl = "http://localhost:8080"; - baseFileUrl = "http://localhost:9000"; - baseAiUrl = "http://localhost:11434"; + // baseApiUrl = "http://localhost:8080"; + // baseFileUrl = "http://localhost:9000"; + // baseAiUrl = "http://localhost:11434"; break; } case Enviroment.prod: diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/claim_statement_window2.dart similarity index 99% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart rename to Frontend/lib/mih_packages/patient_profile/pat_profile/components/claim_statement_window2.dart index cb06b1e3..b203a658 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/claim_statement_window2.dart @@ -126,11 +126,6 @@ class _ClaimStatementWindowState extends State { return MihValidationServices().isEmpty(value); }, ), - // MIHDateField( - // controller: _serviceDateController, - // lableText: "Date of Service", - // required: true, - // ), const SizedBox(height: 10), MihRadioOptions( controller: _serviceDescController, diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart index 82b5c932..6721e147 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart @@ -10,7 +10,7 @@ import 'package:mzansi_innovation_hub/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/claim_statement_file.dart'; import 'package:mzansi_innovation_hub/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/claim_statement_window2.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/list_builders/build_claim_statement_files_list.dart'; import 'package:flutter/material.dart'; From 9cfe23b970e724e1b3e54ef61cffdec1e6f26146 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 13:10:25 +0200 Subject: [PATCH 30/41] rename --- ...claim_statement_window2.dart => claim_statement_window.dart} | 0 .../pat_profile/package_tools/patient_claim_or_statement.dart | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename Frontend/lib/mih_packages/patient_profile/pat_profile/components/{claim_statement_window2.dart => claim_statement_window.dart} (100%) diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/claim_statement_window2.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/claim_statement_window.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/components/claim_statement_window2.dart rename to Frontend/lib/mih_packages/patient_profile/pat_profile/components/claim_statement_window.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart index 6721e147..0e197c38 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart @@ -10,7 +10,7 @@ import 'package:mzansi_innovation_hub/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/claim_statement_file.dart'; import 'package:mzansi_innovation_hub/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/claim_statement_window2.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/claim_statement_window.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/list_builders/build_claim_statement_files_list.dart'; import 'package:flutter/material.dart'; From 5f68fc2a05229de7d5e77cc682e7780f124fba7f Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 13:29:03 +0200 Subject: [PATCH 31/41] delete time input --- .../mih_time_input.dart | 170 ------------------ 1 file changed, 170 deletions(-) delete mode 100644 Frontend/lib/mih_components/mih_inputs_and_buttons/mih_time_input.dart diff --git a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_time_input.dart b/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_time_input.dart deleted file mode 100644 index 78606a1c..00000000 --- a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_time_input.dart +++ /dev/null @@ -1,170 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../main.dart'; - -class MIHTimeField extends StatefulWidget { - final TextEditingController controller; - final String lableText; - final bool required; - - const MIHTimeField({ - super.key, - required this.controller, - required this.lableText, - required this.required, - }); - - @override - State createState() => _MIHDateFieldState(); -} - -class _MIHDateFieldState extends State { - final FocusNode _focus = FocusNode(); - bool startup = true; - - Future _selectTime(BuildContext context) async { - TimeOfDay? picked = await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - builder: (context, child) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true), - child: child as Widget, - ); - }, - ); - if (picked != null) { - String hours = ""; - String minutes = ""; - setState(() { - if (picked.hour <= 9) { - hours = "0${picked.hour}"; - } else { - hours = "${picked.hour}"; - } - - if (picked.minute <= 9) { - minutes = "0${picked.minute}"; - } else { - minutes = "${picked.minute}"; - } - - widget.controller.text = "$hours:$minutes"; - }); - } - } - - Widget setRequiredText() { - if (widget.required) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "*", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor()), - ), - const SizedBox( - width: 8.0, - ), - Text(widget.lableText, - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor())), - ], - ); - } else { - return Text(widget.lableText, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor())); - } - } - - void _onFocusChange() { - setState(() { - startup = false; - }); - } - - String? get _errorText { - final text = widget.controller.text; - if (startup) { - return null; - } - if (!widget.required) { - return null; - } - if (text.isEmpty) { - return "${widget.lableText} is required"; - } - return null; - } - - @override - void dispose() { - _focus.dispose(); - super.dispose(); - } - - @override - void initState() { - _focus.addListener(_onFocusChange); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return TextField( - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - controller: widget.controller, - readOnly: true, - obscureText: false, - focusNode: _focus, - onChanged: (_) => setState(() { - startup = false; - }), - decoration: InputDecoration( - errorText: _errorText, - errorStyle: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - fontWeight: FontWeight.bold), - label: setRequiredText(), - //labelText: widget.lableText, - //labelStyle: const TextStyle(color: Colors.blueAccent), - prefixIcon: Icon( - Icons.access_alarm, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - filled: true, - //hintText: hintText, - //hintStyle: TextStyle(color: Colors.blueGrey[400]), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ), - ), - onTap: () { - _selectTime(context); - }, - ); - } -} From ccd9c5ae05ad21597eadbbc968aca4ab401beab5 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 15:39:49 +0200 Subject: [PATCH 32/41] create new dropdown --- .../mih_dropdwn_field.dart | 207 ++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart diff --git a/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart b/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart new file mode 100644 index 00000000..2c22327f --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart @@ -0,0 +1,207 @@ +import 'package:flutter/material.dart'; +import '../../main.dart'; + +class MihDropdownField extends StatefulWidget { + final TextEditingController controller; + final String hintText; + final bool requiredText; + final List dropdownOptions; + final bool editable; + final bool enableSearch; + final FormFieldValidator? validator; + + const MihDropdownField({ + super.key, + required this.controller, + required this.hintText, + required this.dropdownOptions, + required this.requiredText, + required this.editable, + required this.enableSearch, + this.validator, + }); + + @override + State createState() => _MihDropdownFieldState(); +} + +class _MihDropdownFieldState extends State { + late List> menu; + + List> buildMenuOptions(List options) { + List> menuList = []; + final theme = MzanziInnovationHub.of(context)!.theme; + for (final i in options) { + menuList.add(DropdownMenuEntry( + value: i, + label: i, + style: ButtonStyle( + foregroundColor: WidgetStatePropertyAll(theme.primaryColor()), + ), + )); + } + return menuList; + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + menu = buildMenuOptions(widget.dropdownOptions); + } + + @override + void initState() { + super.initState(); + menu = widget.dropdownOptions + .map((e) => DropdownMenuEntry(value: e, label: e)) + .toList(); + } + + @override + Widget build(BuildContext context) { + final theme = MzanziInnovationHub.of(context)!.theme; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.hintText, + style: TextStyle( + color: theme.secondaryColor(), + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + if (!widget.requiredText) + Text( + "(Optional)", + style: TextStyle( + color: theme.secondaryColor(), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 4), + FormField( + validator: widget.validator, + autovalidateMode: AutovalidateMode.onUserInteraction, + initialValue: widget.controller.text, + builder: (field) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Theme( + data: Theme.of(context).copyWith( + textSelectionTheme: TextSelectionThemeData( + selectionColor: + theme.primaryColor().withValues(alpha: 0.3), + selectionHandleColor: theme.primaryColor(), + ), + ), + child: DropdownMenu( + controller: widget.controller, + dropdownMenuEntries: menu, + enableSearch: widget.enableSearch, + enableFilter: widget.enableSearch, + enabled: widget.editable, + menuHeight: 400, + expandedInsets: EdgeInsets.zero, + textStyle: TextStyle( + color: theme.primaryColor(), + fontWeight: FontWeight.w500, + ), + trailingIcon: Icon( + Icons.arrow_drop_down, + color: theme.primaryColor(), + ), + selectedTrailingIcon: Icon( + Icons.arrow_drop_up, + color: theme.primaryColor(), + ), + leadingIcon: IconButton( + onPressed: () { + widget.controller.clear(); + field.didChange(''); + }, + icon: Icon( + Icons.delete_outline_rounded, + color: theme.primaryColor(), + ), + ), + onSelected: (String? selectedValue) { + field.didChange(selectedValue); + }, + menuStyle: MenuStyle( + backgroundColor: + WidgetStatePropertyAll(theme.secondaryColor()), + side: WidgetStatePropertyAll( + BorderSide(color: theme.primaryColor(), width: 1.0), + ), + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 10), // Increase for more roundness + ), + ), + ), + inputDecorationTheme: InputDecorationTheme( + errorStyle: const TextStyle(height: 0, fontSize: 0), + contentPadding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 8.0), + filled: true, + fillColor: theme.secondaryColor(), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide.none, + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide( + color: field.hasError + ? theme.errorColor() + : theme.secondaryColor(), + width: 3.0, + ), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide( + color: theme.errorColor(), + width: 3.0, + ), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide( + color: theme.errorColor(), + width: 3.0, + ), + ), + ), + ), + ), + if (field.hasError) + Padding( + padding: const EdgeInsets.only(left: 8.0, top: 4.0), + child: Text( + field.errorText ?? '', + style: TextStyle( + fontSize: 12, + color: theme.errorColor(), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ); + }, + ), + ], + ); + } +} From eb349d3ba36a4c6d9a1c24f85274478341c275d4 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 15:40:10 +0200 Subject: [PATCH 33/41] use new dropdown in example --- .../package_tools/package_tool_one.dart | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) 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 84229de1..adfb604b 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 @@ -7,6 +7,7 @@ import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_date_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_numeric_stepper.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; @@ -44,6 +45,7 @@ class _PackageToolOneState extends State { TextEditingController _textFieldSixController = TextEditingController(); TextEditingController _textFieldSevenController = TextEditingController(); TextEditingController _textFieldEightController = TextEditingController(); + TextEditingController _textFieldNineController = TextEditingController(); bool switchpositioin = true; final FocusNode searchFocusNode = FocusNode(); final _formKey = GlobalKey(); @@ -273,6 +275,30 @@ class _PackageToolOneState extends State { radioOptions: const ["Option 1", "Option 2"], ), const SizedBox(height: 10), + MihDropdownField( + controller: _textFieldNineController, + hintText: "Dropdown", + dropdownOptions: const [ + "Option 1", + "Option 2", + "Option 3", + "Option 4", + "Option 5", + "Option 6", + "Option 7", + "Option 8", + "Option 9", + "Option 10", + "Option 11", + ], + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, + ), + const SizedBox(height: 10), MihDateField( controller: _textFieldSevenController, labelText: "Date Field", From 11ffcc9740912196d822d3396c2c47b70a19ab5a Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 15:40:20 +0200 Subject: [PATCH 34/41] use new dropdown in Access --- .../package_tools/mih_access_requests.dart | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Frontend/lib/mih_packages/access_review/package_tools/mih_access_requests.dart b/Frontend/lib/mih_packages/access_review/package_tools/mih_access_requests.dart index 67c0ffd9..e77038f9 100644 --- a/Frontend/lib/mih_packages/access_review/package_tools/mih_access_requests.dart +++ b/Frontend/lib/mih_packages/access_review/package_tools/mih_access_requests.dart @@ -1,10 +1,11 @@ +import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; import 'package:flutter/material.dart'; import '../../../main.dart'; import '../../../mih_apis/mih_api_calls.dart'; -import '../../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import '../../../mih_components/mih_layout/mih_action.dart'; import '../../../mih_components/mih_layout/mih_header.dart'; import '../../../mih_components/mih_pop_up_messages/mih_loading_circle.dart'; @@ -133,25 +134,30 @@ class _MihAccessRequestState extends State { children: [ Row( mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.max, children: [ Flexible( - child: MIHDropdownField( + child: MihDropdownField( controller: filterController, - hintText: "Access Types", + hintText: "Access Type", dropdownOptions: const [ "All", "Approved", "Pending", "Declined", - "Cancelled" + "Cancelled", ], - required: true, + requiredText: true, editable: true, - enableSearch: false, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), ), IconButton( + iconSize: 35, onPressed: () { setState(() { forceRefresh = true; From 8924bc5af2df2553a4a6897cafc318bc9e2d3fe2 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 15:48:31 +0200 Subject: [PATCH 35/41] use new dropdown in Mzansai Ai --- .../mzansi_ai/package_tools/ai_chat.dart | 79 ++++++++++++------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart index 8d070e00..04242c2e 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart @@ -1,9 +1,9 @@ import 'dart:async'; import 'dart:convert'; - import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_numeric_stepper.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; @@ -397,42 +397,67 @@ class _AiChatState extends State { const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, children: [ SizedBox( width: 230, - child: MIHDropdownField( + child: MihDropdownField( controller: _ttsVoiceController, - hintText: "AI Voice", + hintText: "Dropdown", dropdownOptions: _voicesString, - required: true, editable: true, - enableSearch: false, + enableSearch: true, + requiredText: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), ), const SizedBox(width: 10), - Padding( - padding: const EdgeInsets.all(5.0), - child: Container( - //color: MzanziInnovationHub.of(context)!.theme.successColor(), - decoration: BoxDecoration( - color: MzanziInnovationHub.of(context)! - .theme - .successColor(), - borderRadius: const BorderRadius.all( - Radius.circular(100), + 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), ), + ], + ), + child: Padding( + padding: const EdgeInsets.only( + top: 2.0, + left: 5.0, ), - child: IconButton( - color: MzanziInnovationHub.of(context)! - .theme - .primaryColor(), - onPressed: () { - print("Start TTS now"); - - _speakText( - "This is the sample of the Mzansi A.I Voice."); - }, - icon: const Icon(Icons.volume_up), + child: SizedBox( + width: 50, + height: 50, + child: IconButton.filled( + style: ButtonStyle( + backgroundColor: + WidgetStateProperty.all( + MzanziInnovationHub.of(context)! + .theme + .successColor()), + ), + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + iconSize: 25, + onPressed: () { + print("Start TTS now"); + _speakText( + "This is the sample of the Mzansi A.I Voice."); + }, + icon: const Icon( + Icons.volume_up, + ), + ), ), ), ), From 99c434ec93ffef27ebb91442c9c959646a570c4e Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 15:50:17 +0200 Subject: [PATCH 36/41] use new dropdown in Mzansai Ai pt2 --- Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart index 04242c2e..2f382ea9 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart @@ -403,7 +403,7 @@ class _AiChatState extends State { width: 230, child: MihDropdownField( controller: _ttsVoiceController, - hintText: "Dropdown", + hintText: "AI Voice", dropdownOptions: _voicesString, editable: true, enableSearch: true, From a3a0315a49eae7a3017257cb1e191f9f7b44cb05 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 16:04:47 +0200 Subject: [PATCH 37/41] use new dropdown in Business profile --- .../builders/build_employee_list.dart | 25 +++-- .../builders/build_user_list.dart | 25 +++-- .../package_tools/mih_business_details.dart | 11 +- .../package_tools/mih_my_business_user.dart | 11 +- .../profile_business_add.dart | 101 ++++-------------- 5 files changed, 68 insertions(+), 105 deletions(-) diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart index 8f907457..896e501a 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart @@ -3,8 +3,9 @@ import 'dart:convert'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; @@ -213,22 +214,28 @@ class _BuildEmployeeListState extends State { hintText: "Surname", ), const SizedBox(height: 15.0), - MIHDropdownField( + MihDropdownField( controller: typeController, hintText: "Title", - dropdownOptions: const ["Doctor", "Assistant"], - required: true, + dropdownOptions: const ["Doctor", "Assistant", "Other"], editable: true, - enableSearch: false, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, ), const SizedBox(height: 10.0), - MIHDropdownField( + MihDropdownField( controller: accessController, - hintText: "Access", + hintText: "Access Type", dropdownOptions: const ["Full", "Partial"], - required: true, editable: true, - enableSearch: false, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, ), const SizedBox(height: 20.0), Center( diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart index c2709027..be04d1c4 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart @@ -2,8 +2,9 @@ import 'dart:convert'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; @@ -168,22 +169,28 @@ class _BuildUserListState extends State { hintText: "Email", ), const SizedBox(height: 15.0), - MIHDropdownField( + MihDropdownField( controller: typeController, hintText: "Title", - dropdownOptions: const ["Doctor", "Assistant"], - required: true, + dropdownOptions: const ["Doctor", "Assistant", "Other"], editable: true, - enableSearch: false, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, ), const SizedBox(height: 10.0), - MIHDropdownField( + MihDropdownField( controller: accessController, - hintText: "Access", + hintText: "Access Type", dropdownOptions: const ["Full", "Partial"], - required: true, editable: true, - enableSearch: false, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, ), const SizedBox(height: 15.0), Center( diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart index 0d2773cc..b83a9f3b 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart @@ -6,9 +6,9 @@ import 'package:mzansi_innovation_hub/mih_apis/mih_business_details_apis.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_file_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_location_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; @@ -304,13 +304,16 @@ class _MihBusinessDetailsState extends State { }, ), const SizedBox(height: 15), - MIHDropdownField( + MihDropdownField( controller: typeController, hintText: "Business Type", dropdownOptions: const ["Doctors Office", "Other"], - required: true, editable: true, - enableSearch: false, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, ), const SizedBox(height: 10), MihTextFormField( diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart index 06d64467..bd94bcd6 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart @@ -5,9 +5,9 @@ import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_file_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_my_business_user_apis.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; @@ -252,13 +252,16 @@ class _MihMyBusinessUserState extends State { ), ), const SizedBox(height: 20), - MIHDropdownField( + MihDropdownField( controller: titleDropdownController, hintText: "Title", dropdownOptions: const ["Doctor", "Assistant", "Other"], - required: true, editable: true, - enableSearch: false, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, ), const SizedBox(height: 10), MihTextFormField( diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart index b746bdcb..4e9613de 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart @@ -8,12 +8,12 @@ import 'package:mzansi_innovation_hub/mih_apis/mih_file_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_location_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_my_business_user_apis.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_header.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_layout_builder.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; @@ -66,25 +66,6 @@ class _ProfileBusinessAddState extends State { final _formKey = GlobalKey(); late String env; - // Future uploadSelectedFile( - // PlatformFile file, TextEditingController controller) async { - // var token = await supertokens.getaccesstoken(); - // var request = http2.multipartrequest( - // 'post', uri.parse("${appenviroment.baseapiurl}/minio/upload/file/")); - // request.headers['accept'] = 'application/json'; - // request.headers['authorization'] = 'bearer $token'; - // request.headers['content-type'] = 'multipart/form-data'; - // request.fields['app_id'] = widget.signedinuser.app_id; - // request.fields['folder'] = "business_files"; - // request.files.add(await http2.multipartfile.frombytes('file', file.bytes!, - // filename: file.name.replaceall(regexp(r' '), '-'))); - // var response1 = await request.send(); - // if (response1.statuscode == 200) { - // } else { - // internetconnectionpopup(); - // } - // } - Future uploadFile(String id, PlatformFile? selectedFile) async { print("Inside uploud file method"); int uploadStatusCode = 0; @@ -113,27 +94,8 @@ class _ProfileBusinessAddState extends State { accessController.text, context, ); - // var response = await http.post( - // Uri.parse("$baseAPI/business-user/insert/"), - // headers: { - // "Content-Type": "application/json; charset=UTF-8" - // }, - // body: jsonEncode({ - // "business_id": business_id, - // "app_id": widget.signedInUser.app_id, - // "signature": signtureController.text, - // "sig_path": - // "${widget.signedInUser.app_id}/business_files/${signtureController.text}", - // "title": titleController.text, - // "access": accessController.text, - // }), - // ); print("Status code: $statusCode"); if (statusCode == 201) { - // uploadSelectedFile(selectedSignature, signtureController); - // bool successfullyUploadedFile = - // await uploadFile(business_id, selectedSignature); - // if (successfullyUploadedFile) { Navigator.of(context).pop(); Navigator.of(context).popAndPushNamed( '/', @@ -142,9 +104,6 @@ class _ProfileBusinessAddState extends State { String message = "Your business profile is now live! You can now start connecting with customers and growing your business."; successPopUp(message); - // } else { - // internetConnectionPopUp(); - // } } else { internetConnectionPopUp(); } @@ -165,35 +124,10 @@ class _ProfileBusinessAddState extends State { logonameController.text, context, ); - // var response = await http.post( - // Uri.parse("$baseAPI/business/insert/"), - // headers: { - // "Content-Type": "application/json; charset=UTF-8" - // }, - // body: jsonEncode({ - // "Name": nameController.text, - // "type": typeController.text, - // "registration_no": regController.text, - // "logo_name": logonameController.text, - // "logo_path": - // "${widget.signedInUser.app_id}/business_files/${logonameController.text}", - // "contact_no": contactController.text, - // "bus_email": emailController.text, - // "gps_location": locationController.text, - // "practice_no": practiceNoController.text, - // "vat_no": vatNoController.text, - // }), - // ); print(response.body); if (response.statusCode == 201) { var businessResponse = jsonDecode(response.body); - // bool successfullyUploadedFile = - // await uploadFile(widget.signedInUser.app_id, selectedSignature); - // if (successfullyUploadedFile) { createBusinessUserAPICall(businessResponse['business_id']); - // } else { - // internetConnectionPopUp(); - // } } else { internetConnectionPopUp(); } @@ -370,13 +304,16 @@ class _ProfileBusinessAddState extends State { }, ), const SizedBox(height: 15.0), - MIHDropdownField( + MihDropdownField( controller: typeController, hintText: "Business Type", dropdownOptions: const ["Doctors Office", "Other"], - required: true, editable: true, - enableSearch: false, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, ), const SizedBox(height: 10.0), ValueListenableBuilder( @@ -520,13 +457,16 @@ class _ProfileBusinessAddState extends State { .theme .secondaryColor()), const SizedBox(height: 10.0), - MIHDropdownField( + MihDropdownField( controller: titleController, hintText: "Title", - dropdownOptions: const ["Doctor", "Assistant"], - required: true, + dropdownOptions: const ["Doctor", "Assistant", "Other"], editable: true, - enableSearch: false, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, ), const SizedBox(height: 10.0), MihTextFormField( @@ -561,13 +501,16 @@ class _ProfileBusinessAddState extends State { }, ), const SizedBox(height: 15.0), - MIHDropdownField( + MihDropdownField( controller: accessController, - hintText: "Access", + hintText: "Access Type", dropdownOptions: const ["Full", "Partial"], - required: true, - editable: false, - enableSearch: false, + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, ), const SizedBox(height: 20.0), Center( From e28a402de7cfa5e62dec4d7783460866ac041f83 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 16:04:54 +0200 Subject: [PATCH 38/41] update test --- .../Example/package_tools/package_tool_one.dart | 8 -------- 1 file changed, 8 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 adfb604b..e280d651 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 @@ -282,14 +282,6 @@ class _PackageToolOneState extends State { "Option 1", "Option 2", "Option 3", - "Option 4", - "Option 5", - "Option 6", - "Option 7", - "Option 8", - "Option 9", - "Option 10", - "Option 11", ], editable: true, enableSearch: true, From e2573ee6358c8935c042fbd4db95b304cbbc99d5 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 16:07:15 +0200 Subject: [PATCH 39/41] use new dropdown in wallet --- .../mzansi_wallet/package_tools/mih_cards.dart | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart index 9459f3be..4241dddc 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart @@ -3,9 +3,9 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_mzansi_wallet_apis.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; @@ -108,9 +108,15 @@ class _MihCardsState extends State { MihForm( formKey: _formKey, formFields: [ - MIHDropdownField( + MihDropdownField( controller: shopController, hintText: "Shop Name", + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, dropdownOptions: const [ "+More", "Apple Tree", @@ -157,9 +163,6 @@ class _MihCardsState extends State { "Woermann Brock", "Woolworths" ], - required: true, - editable: true, - enableSearch: false, ), ValueListenableBuilder( valueListenable: shopName, From 3538f2454ca70e746da6f3fc259fca4ead430709 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 16:15:27 +0200 Subject: [PATCH 40/41] fix button alignment --- .../package_tools/patient_documents.dart | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart index ea894653..8bb3afc0 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart @@ -238,6 +238,7 @@ class _PatientDocumentsState extends State { ? EdgeInsets.symmetric(horizontal: width * 0.05) : const EdgeInsets.symmetric(horizontal: 0), child: Column( + mainAxisAlignment: MainAxisAlignment.center, children: [ MihForm( formKey: _formKey, @@ -298,27 +299,29 @@ class _PatientDocumentsState extends State { ], ), const SizedBox(height: 20), - MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - submitDocUploadForm(); - // uploadSelectedFile(selected); - Navigator.pop(context); - } else { - MihAlertServices().formNotFilledCompletely(context); - } - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.successColor(), - width: 300, - child: Text( - "Add File", - style: TextStyle( - color: MzanziInnovationHub.of(context)! - .theme - .primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitDocUploadForm(); + // uploadSelectedFile(selected); + Navigator.pop(context); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.successColor(), + width: 300, + child: Text( + "Add File", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), ), ), ), From 7804d6e369b094d72b77eabf15befbbdc972e417 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 16:44:37 +0200 Subject: [PATCH 41/41] remove old dropdown --- .../mih_dropdown_input.dart | 219 ------------------ 1 file changed, 219 deletions(-) delete mode 100644 Frontend/lib/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart diff --git a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart b/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart deleted file mode 100644 index ef136c6e..00000000 --- a/Frontend/lib/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart +++ /dev/null @@ -1,219 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../main.dart'; - -class MIHDropdownField extends StatefulWidget { - final TextEditingController controller; - final String hintText; - final bool required; - final List dropdownOptions; - // final void Function(String?)? onSelect; - final bool editable; - final bool enableSearch; - - const MIHDropdownField({ - super.key, - required this.controller, - required this.hintText, - required this.dropdownOptions, - required this.required, - required this.editable, - required this.enableSearch, - // this.onSelect, - }); - - @override - State createState() => _MIHDropdownFieldState(); -} - -class _MIHDropdownFieldState extends State { - //var dropbownItems = ["Dr.", "Assistant"]; - bool startup = true; - final FocusNode _focus = FocusNode(); - late List> menu; - - Widget setRequiredText() { - if (widget.required) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "*", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor()), - ), - const SizedBox( - width: 8.0, - ), - Text(widget.hintText, - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor())), - ], - ); - } else { - return Text(widget.hintText, - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor())); - } - } - - void _onFocusChange() { - setState(() { - startup = false; - }); - // widget.onSelect; - } - - String? get _errorText { - final text = widget.controller.text; - if (startup) { - return null; - } - if (!widget.required) { - return null; - } - if (text.isEmpty) { - return "${widget.hintText} is required"; - } - return null; - } - - List> buidMenueOptions(List options) { - List> menueList = []; - for (final i in options) { - menueList.add(DropdownMenuEntry( - value: i, - label: i, - style: ButtonStyle( - foregroundColor: WidgetStatePropertyAll( - MzanziInnovationHub.of(context)!.theme.secondaryColor())))); - } - return menueList; - } - - @override - void dispose() { - _focus.dispose(); - super.dispose(); - } - - @override - void initState() { - menu = buidMenueOptions(widget.dropdownOptions); - _focus.addListener(_onFocusChange); - _focus.canRequestFocus = widget.enableSearch; - super.initState(); - } - - // bool makeEditable() { - @override - Widget build(BuildContext context) { - return DropdownMenu( - enableSearch: widget.enableSearch, - enableFilter: widget.enableSearch, - // requestFocusOnTap: true, - initialSelection: widget.controller.text, - enabled: widget.editable, - trailingIcon: Icon( - Icons.arrow_drop_down, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - selectedTrailingIcon: Icon( - Icons.arrow_drop_up, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - textStyle: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - menuHeight: 300, - controller: widget.controller, - expandedInsets: EdgeInsets.zero, - label: setRequiredText(), - errorText: _errorText, - - focusNode: _focus, - onSelected: (selected) { - _onFocusChange(); - // if (widget.editable == false) { - // return false; - // } - }, - leadingIcon: IconButton( - onPressed: () { - setState(() { - startup = false; - }); - widget.controller.clear(); - }, - icon: Icon( - Icons.delete_outline_rounded, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - menuStyle: MenuStyle( - backgroundColor: WidgetStatePropertyAll( - MzanziInnovationHub.of(context)!.theme.primaryColor()), - side: WidgetStatePropertyAll( - BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0), - ), - ), - - inputDecorationTheme: InputDecorationTheme( - filled: true, - errorStyle: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - fontWeight: FontWeight.bold), - fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 2.0, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - disabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 2.0, - ), - ), - outlineBorder: BorderSide( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ), - dropdownMenuEntries: menu, - // const >[ - // DropdownMenuEntry(value: "Dr.", label: "Dr."), - // DropdownMenuEntry(value: "Assistant", label: "Assistant"), - // ], - ); - } -} - -// filled: true, -// hintText: hintText, -// hintStyle: TextStyle(color: Colors.blueGrey[400]), -// enabledBorder: const OutlineInputBorder( -// borderSide: BorderSide( -// color: Colors.blueAccent, -// width: 2.0, -// ), -// ), -// focusedBorder: const OutlineInputBorder( -// borderSide: BorderSide(color: Colors.blue),