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) { 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_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), 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()), - ), - ), - ); - } -} 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); - }, - ); - } -} 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..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 @@ -6,15 +6,21 @@ 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_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'; 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'; 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 { const PackageToolOne({super.key}); @@ -35,6 +41,12 @@ class _PackageToolOneState extends State { TextEditingController _textFieldTwoController = TextEditingController(); TextEditingController _textFieldThreeController = TextEditingController(); TextEditingController _textFieldFourController = TextEditingController(); + TextEditingController _textFieldFiveController = TextEditingController(); + TextEditingController _textFieldSixController = TextEditingController(); + TextEditingController _textFieldSevenController = TextEditingController(); + TextEditingController _textFieldEightController = TextEditingController(); + TextEditingController _textFieldNineController = TextEditingController(); + bool switchpositioin = true; final FocusNode searchFocusNode = FocusNode(); final _formKey = GlobalKey(); @@ -220,6 +232,83 @@ 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), + MihToggle( + hintText: "Toggle", + initialPostion: switchpositioin, + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + secondaryFillColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + readOnly: false, + onChange: (value) { + setState(() { + switchpositioin = value; + }); + print("Toggle Value: $switchpositioin"); + }, + ), + 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), + MihDropdownField( + controller: _textFieldNineController, + hintText: "Dropdown", + dropdownOptions: const [ + "Option 1", + "Option 2", + "Option 3", + ], + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, + ), + 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)! 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_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, + ), + ), + ), + ], + ); + }, + ), + ], + ); + } +} 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..3afeaf06 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_numeric_stepper.dart @@ -0,0 +1,214 @@ +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(); + _currentValue = + int.tryParse(widget.controller.text) ?? widget.minValue ?? 0; + widget.controller.text = _currentValue.toString(); + print("Current Value: $_currentValue"); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + children: [ + Text( + widget.hintText, + style: TextStyle( + fontWeight: FontWeight.bold, + color: widget.fillColor, + fontSize: 18, + ), + ), + ], + ), + const SizedBox(height: 4), + 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) || + (widget.maxValue != null && + _currentValue > widget.maxValue!), + child: const SizedBox( + height: 21, + ), + ), + ], + ), + const SizedBox(width: 15), + Expanded( + child: MihTextFormField( + width: widget.width, + fillColor: widget.fillColor, + inputColor: widget.inputColor, + controller: widget.controller, + hintText: null, + requiredText: widget.requiredText, + readOnly: true, + numberMode: true, + textIputAlignment: TextAlign.center, + validator: (value) { + if (widget.validationOn) { + return MihValidationServices().validateNumber( + value, widget.minValue, widget.maxValue); + } + return null; + }, + ), + ), + const SizedBox(width: 10), + 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) || + (widget.maxValue != null && + _currentValue > widget.maxValue!), + child: const SizedBox( + height: 21, + ), + ), + ], + ), + ], + ), + ], + ); + } +} 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..5f7dfa40 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_radio_options.dart @@ -0,0 +1,140 @@ +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(); + 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]; + } + +// 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), + child: Container( + decoration: BoxDecoration( + color: widget.fillColor, + borderRadius: BorderRadius.circular(8.0), + ), + child: Column( + children: widget.radioOptions.map((option) { + return GestureDetector( + onTap: () { + _onChanged(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: selection, + onChanged: _onChanged, + 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 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, + ), + ), + ), + ], + ), + const SizedBox(height: 4), + displayRadioOptions(currentSelection), + ], + ); + }); + } +} 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..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 @@ -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; @@ -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 @@ -98,31 +100,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, + 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), FormField( @@ -141,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_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, + ), + ), + ), + ], + ); + }, + ), + ], + ), + ), + ); + } +} 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..5872bf6c --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_toggle.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; + +class MihToggle extends StatefulWidget { + final String hintText; + final bool initialPostion; + final Color fillColor; + final Color secondaryFillColor; + final bool? readOnly; + final void Function(bool) onChange; + const MihToggle({ + super.key, + required this.hintText, + required this.initialPostion, + required this.fillColor, + required this.secondaryFillColor, + this.readOnly, + 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: 18, + ), + ), + ), + const SizedBox(width: 10), + Switch( + value: widget.initialPostion, + 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, + ), + ], + ); + } +} 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/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; 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 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..b4191d3f 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,7 @@ class _TipCalcState extends State { TextEditingController splitBillController = TextEditingController(); TextEditingController noPeopleController = TextEditingController(); final ValueNotifier splitValue = ValueNotifier(""); + late bool splitPosition; final _formKey = GlobalKey(); String tip = ""; String total = ""; @@ -230,6 +232,8 @@ class _TipCalcState extends State { void initState() { super.initState(); splitBillController.text = "No"; + noPeopleController.text = "2"; + 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,40 @@ 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) { + 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( valueListenable: splitValue, builder: (BuildContext context, String value, Widget? child) { @@ -316,33 +330,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), ], 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( 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..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 @@ -1,13 +1,14 @@ 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'; 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,112 +371,116 @@ 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), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SizedBox( - width: 230, - child: MIHDropdownField( - controller: _ttsVoiceController, - hintText: "AI Voice", - dropdownOptions: _voicesString, - required: true, - editable: true, - enableSearch: false, - ), - ), - 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), - ), - ), - 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), - ), - ), - ), - ], - ), - const SizedBox(height: 15), + const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, children: [ - IconButton.filled( - onPressed: () { - setState(() { - _chatFrontSize -= 1; - _fontSizeController.text = - _chatFrontSize.ceil().toString(); - }); - }, - icon: const Icon( - Icons.remove, + SizedBox( + width: 230, + child: MihDropdownField( + controller: _ttsVoiceController, + hintText: "AI Voice", + dropdownOptions: _voicesString, + editable: true, + enableSearch: true, + requiredText: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), ), 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", + 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: 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, + ), + ), + ), + ), ), - const SizedBox(width: 10), - IconButton.filled( - onPressed: () { - setState(() { - _chatFrontSize += 1; - _fontSizeController.text = - _chatFrontSize.ceil().toString(); - }); - }, - icon: const Icon( - Icons.add, + ], + ), + const SizedBox(height: 10), + Row( + children: [ + 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 +542,12 @@ class _AiChatState extends State { } } + void fontSizeChanged() { + setState(() { + _chatFrontSize = double.parse(_fontSizeController.text); + }); + } + @override void dispose() { // TODO: implement dispose @@ -545,12 +556,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 +663,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( 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( 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( 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, 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/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/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(); 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( 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 similarity index 81% 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_window.dart index 61e185c9..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_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_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'; 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( @@ -118,23 +118,28 @@ 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); + }, ), 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 +149,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 +196,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 +207,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 +215,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 +240,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 +254,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 +405,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 +433,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 +490,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 +516,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 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_claim_or_statement.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart index 82b5c932..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_Window.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'; 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..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 @@ -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_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_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_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,8 @@ class _PatientDocumentsState extends State { final noRepeatsController = TextEditingController(); final outputController = TextEditingController(); late PlatformFile? selected; + final _formKey = GlobalKey(); + final _formKey2 = GlobalKey(); late String env; Future submitDocUploadForm() async { @@ -217,7 +222,7 @@ class _PatientDocumentsState extends State { } } - void uploudFilePopUp() { + void uploudFilePopUp(double width) { showDialog( context: context, barrierDismissible: false, @@ -227,59 +232,103 @@ 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"); - }, - ); - } - }, - 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, - ), + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + 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: 20), + 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, + ), + ), + ), + ), + ], ), - ), - ], + ], + ), ), ), ); @@ -297,37 +346,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, + ), + ), + ), + ), + ], ), ], ), @@ -344,11 +423,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( @@ -391,7 +470,7 @@ class _PatientDocumentsState extends State { } } - Widget getMenu() { + Widget getMenu(double width) { if (widget.type == "personal") { return Positioned( right: 10, @@ -415,7 +494,7 @@ class _PatientDocumentsState extends State { backgroundColor: MzanziInnovationHub.of(context)!.theme.successColor(), onTap: () { - uploudFilePopUp(); + uploudFilePopUp(width); }, ) ], @@ -444,7 +523,7 @@ class _PatientDocumentsState extends State { backgroundColor: MzanziInnovationHub.of(context)!.theme.successColor(), onTap: () { - uploudFilePopUp(); + uploudFilePopUp(width); }, ), SpeedDialChild( @@ -489,70 +568,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 +618,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 +657,7 @@ class _PatientDocumentsState extends State { }, ), ), - getMenu(), + getMenu(width), ], ); } 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(); }