diff --git a/Frontend/lib/main_dev.dart b/Frontend/lib/main_dev.dart index 8b4805ea..60936ced 100644 --- a/Frontend/lib/main_dev.dart +++ b/Frontend/lib/main_dev.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; +import 'package:pwa_install/pwa_install.dart'; import '../mih_env/env.dart'; import '../../main.dart'; import 'package:supertokens_flutter/supertokens.dart'; @@ -14,6 +15,9 @@ void main() async { apiBasePath: "/auth", ); // setUrlStrategy(PathUrlStrategy()); + PWAInstall().setup(installCallback: () { + debugPrint('APP INSTALLED!'); + }); FlutterNativeSplash.remove(); runApp(const MzanziInnovationHub()); } diff --git a/Frontend/lib/main_prod.dart b/Frontend/lib/main_prod.dart index ccae5b4a..c7b3c214 100644 --- a/Frontend/lib/main_prod.dart +++ b/Frontend/lib/main_prod.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; +import 'package:pwa_install/pwa_install.dart'; import '../mih_env/env.dart'; import '../../main.dart'; import 'package:supertokens_flutter/supertokens.dart'; @@ -15,5 +16,8 @@ void main() async { ); // setUrlStrategy(PathUrlStrategy()); FlutterNativeSplash.remove(); + PWAInstall().setup(installCallback: () { + debugPrint('APP INSTALLED!'); + }); runApp(const MzanziInnovationHub()); } diff --git a/Frontend/lib/mih_apis/mih_alert_services.dart b/Frontend/lib/mih_apis/mih_alert_services.dart new file mode 100644 index 00000000..8f9e2a64 --- /dev/null +++ b/Frontend/lib/mih_apis/mih_alert_services.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; + +class MihAlertServices { + void formNotFilledCompletely(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.warning_amber_rounded, + size: 150, + color: MzanziInnovationHub.of(context)!.theme.errorColor(), + ), + alertTitle: "Oops! Looks like some fields are missing.", + alertBody: Column( + children: [ + Text( + "We noticed that some required fields are still empty. To ensure your request is processed smoothly, please fill out all the highlighted fields before submitting the form again.", + style: TextStyle( + color: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + RichText( + text: TextSpan( + style: TextStyle( + color: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + children: [ + TextSpan( + text: "Here's a quick tip: ", + style: TextStyle( + fontStyle: FontStyle.italic, + color: MzanziInnovationHub.of(context)! + .theme + .errorColor())), + const TextSpan( + text: + "Look for fields without the \"(Optional)\" indicator next to them, as these are mandatory."), + ], + ), + ), + ], + ), + alertColour: MzanziInnovationHub.of(context)!.theme.errorColor(), + ); + }, + ); + } +} diff --git a/Frontend/lib/mih_apis/mih_install_services.dart b/Frontend/lib/mih_apis/mih_install_services.dart new file mode 100644 index 00000000..bc2cbdfb --- /dev/null +++ b/Frontend/lib/mih_apis/mih_install_services.dart @@ -0,0 +1,64 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:pwa_install/pwa_install.dart'; +// import 'package:universal_html/js.dart' as js; +import 'package:url_launcher/url_launcher.dart'; + +class MihInstallServices { + String? errorMessage; + + Future launchSocialUrl(Uri linkUrl) async { + if (!await launchUrl(linkUrl)) { + throw Exception('Could not launch $linkUrl'); + } + } + + void installMihTrigger(BuildContext context) { + final isWebAndroid = + kIsWeb && (defaultTargetPlatform == TargetPlatform.android); + final isWebIos = kIsWeb && (defaultTargetPlatform == TargetPlatform.iOS); + if (isWebAndroid) { + launchSocialUrl( + Uri.parse( + "https://play.google.com/store/apps/details?id=za.co.mzansiinnovationhub.mih", + ), + ); + } else if (isWebIos) { + //Show pop up for IOS + launchSocialUrl( + Uri.parse( + "https://apps.apple.com/za/app/mzansi-innovation-hub/id6743310890", + ), + ); + } else if (MzanziInnovationHub.of(context)!.theme.getPlatform() == + "Android") { + //Installed Android App + launchSocialUrl( + Uri.parse( + "https://play.google.com/store/apps/details?id=za.co.mzansiinnovationhub.mih", + ), + ); + } else if (MzanziInnovationHub.of(context)!.theme.getPlatform() == "iOS") { + launchSocialUrl( + Uri.parse( + "https://apps.apple.com/za/app/mzansi-innovation-hub/id6743310890", + ), + ); + } else { + //Web + if (PWAInstall().installPromptEnabled) { + try { + PWAInstall().promptInstall_(); + } catch (e) { + errorMessage = e.toString(); + debugPrint('Error prompting install: $e'); + } + } else { + // Fallback for unsupported platforms + debugPrint('Install prompt not available for this platform.'); + } + // js.context.callMethod("presentAddToHome"); + } + } +} diff --git a/Frontend/lib/mih_apis/mih_validation_services.dart b/Frontend/lib/mih_apis/mih_validation_services.dart new file mode 100644 index 00000000..47601075 --- /dev/null +++ b/Frontend/lib/mih_apis/mih_validation_services.dart @@ -0,0 +1,84 @@ +class MihValidationServices { + String? isEmpty(String? value) { + if (value == null || value.isEmpty) { + return "This field is required"; + } + return null; + } + + String? validateLength(String? value, int maxLength) { + if (value == null || value.isEmpty) { + return "This field is required"; + } + if (value.length > maxLength) { + return "Length must not exceed $maxLength characters"; + } + return null; + } + + String? validateEmail(String? email) { + if (email == null || email.isEmpty) { + return "Email is required"; + } + final emailRegex = + RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'); + if (!emailRegex.hasMatch(email)) { + return "Invalid Email Format"; + } + return null; + } + + String? validateUsername(String? username) { + String? errorMessage = ""; + if (username == null || username.isEmpty) { + errorMessage += "Username is required"; + return errorMessage; + } + if (!RegExp(r'^[a-zA-Z]').hasMatch(username)) { + errorMessage += "\n• Your username should start with a letter."; + } + if (!RegExp(r'^[a-zA-Z0-9_]+$').hasMatch(username)) { + errorMessage += + "\n• You can use letters, numbers, and/or underscores only."; + } + if (username.length < 6 || username.length > 30) { + errorMessage += "\n• Keep it between 6 and 30 characters."; + } + if (RegExp(r'[@#\$]').hasMatch(username)) { + errorMessage += "\n• Avoid special characters like @, #, or \$."; + } + + if (errorMessage.isEmpty) { + return null; // No errors, username is valid + } + return "Let's create a great username for you!$errorMessage"; + } + + String? validatePassword(String? password) { + String? errorMessage = ""; + if (password == null || password.isEmpty) { + errorMessage += "Password is required"; + return errorMessage; + } + if (password.length < 8) { + errorMessage += "\n• Contains at least 8 characters long"; + } + if (!RegExp(r'[A-Z]').hasMatch(password)) { + errorMessage += "\n• Contains at least 1 uppercase letter"; + } + if (!RegExp(r'[a-z]').hasMatch(password)) { + errorMessage += "\n• Contains at least 1 lowercase letter"; + } + if (!RegExp(r'[0-9]').hasMatch(password)) { + errorMessage += "\n• Contains at least 1 digit"; + } + if (!RegExp(r'[!@#$%^&*]').hasMatch(password)) { + errorMessage += "\n• Contains at least 1 special character (!@#\$%^&*)"; + } + if (errorMessage.isEmpty) { + return null; // No errors, password is valid + } + errorMessage = "Let's create a great password for you!$errorMessage"; + return errorMessage; + } +} 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 index afa4d714..301b8ce7 100644 --- 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 @@ -147,16 +147,12 @@ class _MIHTextFieldState extends State { }), 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(), 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 26108ce5..8716ffb2 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 @@ -2,9 +2,11 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.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_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; @@ -12,6 +14,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ 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_search_bar.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; class PackageToolOne extends StatefulWidget { const PackageToolOne({super.key}); @@ -27,7 +30,14 @@ class _PackageToolOneState extends State { TextEditingController _fileNameController = TextEditingController(); TextEditingController _imagefileController = TextEditingController(); TextEditingController _searchController = TextEditingController(); + TextEditingController _textFieldZeroController = TextEditingController(); + TextEditingController _textFieldOneController = TextEditingController(); + TextEditingController _textFieldTwoController = TextEditingController(); + TextEditingController _textFieldThreeController = TextEditingController(); + TextEditingController _textFieldFourController = TextEditingController(); final FocusNode searchFocusNode = FocusNode(); + final _formKey = GlobalKey(); + void showTestFullWindow() { showDialog( context: context, @@ -85,9 +95,10 @@ class _PackageToolOneState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MihPackageToolBody( - borderOn: true, - bodyItem: getBody(), + borderOn: false, + bodyItem: getBody(screenWidth), ); } @@ -110,176 +121,312 @@ class _PackageToolOneState extends State { }); } - Widget getBody() { + Widget getBody(double width) { return Stack( children: [ MihSingleChildScroll( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Hello", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MzanziInnovationHub.of(context)! - .theme - .secondaryColor(), - ), - ), - ], - ), - const SizedBox(height: 20), - MihSearchBar( - controller: _searchController, - hintText: "Ask Mzansi", - // prefixIcon: Icons.search, - prefixIcon: Icons.search, - prefixAltIcon: MihIcons.mzansiAi, - width: 300, - fillColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - hintColor: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - onPrefixIconTap: () { - print("Search Icon Pressed: ${_searchController.text}"); - }, - searchFocusNode: searchFocusNode, - ), - const SizedBox(height: 20), - MihButton( - onPressed: () { - print("Button Pressed"); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - elevation: 10, - width: 300, - child: Text( - "Click Me", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - const SizedBox(height: 40), - MihButton( - onPressed: () { - print("Button Pressed"); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.successColor(), - width: 300, - child: Row( + child: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.delete, - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - ), Text( - "Click Me", + "Hello", + textAlign: TextAlign.center, style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, color: MzanziInnovationHub.of(context)! .theme - .primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + .secondaryColor(), ), ), ], ), - ), - const SizedBox(height: 10), - MihButton( - onPressed: () { - print("Button Pressed"); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 300, - child: Text( - "Click Me", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + const SizedBox(height: 20), + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + width: 200, + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _textFieldZeroController, + multiLineInput: false, + requiredText: false, + hintText: "Username", + validator: (value) { + return MihValidationServices().validateUsername(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _textFieldOneController, + multiLineInput: false, + requiredText: true, + hintText: "Email", + autofillHints: [AutofillHints.email], + validator: (value) { + return MihValidationServices().validateEmail(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _textFieldTwoController, + multiLineInput: false, + requiredText: true, + hintText: "Password", + passwordMode: true, + autofillHints: [AutofillHints.password], + validator: (value) { + return MihValidationServices().validatePassword(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _textFieldThreeController, + multiLineInput: false, + requiredText: true, + hintText: "Numbers Only", + numberMode: true, + validator: (value) => value == null || value.isEmpty + ? 'This Field is required' + : null, + ), + const SizedBox(height: 10), + MihTextFormField( + height: 250, + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _textFieldFourController, + multiLineInput: true, + requiredText: false, + hintText: "Enter Multi Line Text", + ), + const SizedBox(height: 20), + Align( + alignment: Alignment.center, + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + // Process data + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text("Input Valid")), + ); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + elevation: 10, + width: 300, + child: Text( + "Submit Form", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + const SizedBox(height: 10), + Divider( + color: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + thickness: 2, + ), + const SizedBox(height: 10), + MihSearchBar( + controller: _searchController, + hintText: "Ask Mzansi", + // prefixIcon: Icons.search, + prefixIcon: Icons.search, + prefixAltIcon: MihIcons.mzansiAi, + width: 300, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + print("Search Icon Pressed: ${_searchController.text}"); + }, + searchFocusNode: searchFocusNode, + ), + const SizedBox(height: 20), + MihButton( + onPressed: () { + print("Button Pressed"); + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + elevation: 10, + width: 300, + child: Text( + "Click Me", + style: TextStyle( + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), ), ), - ), - const SizedBox(height: 10), - Container( - color: Colors.black, - width: 200, - height: 200, - padding: EdgeInsets.zero, - alignment: Alignment.center, - child: IconButton.filled( - onPressed: () {}, - icon: Icon( - MihIcons.mihLogo, - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), + const SizedBox(height: 40), + MihButton( + onPressed: () { + print("Button Pressed"); + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.successColor(), + width: 300, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.delete, + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + ), + Text( + "Click Me", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ], ), ), - ), - const SizedBox(height: 10), - MihCircleAvatar( - imageFile: imagePreview, - width: 50, - editable: false, - fileNameController: _fileNameController, - userSelectedfile: file, - frameColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - backgroundColor: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - onChange: (selectedImage) { - setState(() { - file = selectedImage; - }); - }, - ), - const SizedBox(height: 10), - MIHTextField( - controller: _fileNameController, - hintText: "Selected Avatar File", - editable: false, - required: false, - ), - const SizedBox(height: 10), - MihImageDisplay( - imageFile: imagePreview, - width: 300, - height: 200, - editable: true, - fileNameController: _imagefileController, - userSelectedfile: imageFile, - onChange: (selectedFile) { - setState(() { - imageFile = selectedFile; - }); - }, - ), - const SizedBox(height: 10), - MIHTextField( - controller: _imagefileController, - hintText: "Selected Image File", - editable: false, - required: false, - ), - ], + const SizedBox(height: 10), + MihButton( + onPressed: () { + print("Button Pressed"); + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.errorColor(), + width: 300, + child: Text( + "Click Me", + style: TextStyle( + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 10), + Container( + color: Colors.black, + width: 200, + height: 200, + padding: EdgeInsets.zero, + alignment: Alignment.center, + child: IconButton.filled( + onPressed: () {}, + icon: Icon( + MihIcons.mihLogo, + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + ), + ), + ), + const SizedBox(height: 10), + MihCircleAvatar( + imageFile: imagePreview, + width: 50, + editable: false, + fileNameController: _fileNameController, + userSelectedfile: file, + frameColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + backgroundColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onChange: (selectedImage) { + setState(() { + file = selectedImage; + }); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _fileNameController, + hintText: "Selected Avatar File", + requiredText: false, + readOnly: false, + ), + const SizedBox(height: 10), + MihImageDisplay( + imageFile: imagePreview, + width: 300, + height: 200, + editable: true, + fileNameController: _imagefileController, + userSelectedfile: imageFile, + onChange: (selectedFile) { + setState(() { + imageFile = selectedFile; + }); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _imagefileController, + hintText: "Selected Image File", + requiredText: false, + readOnly: false, + ), + const SizedBox(height: 10), + ], + ), ), ), Positioned( diff --git a/Frontend/lib/mih_components/mih_package_components/mih_form.dart b/Frontend/lib/mih_components/mih_package_components/mih_form.dart new file mode 100644 index 00000000..6c880b97 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_form.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +class MihForm extends StatefulWidget { + final GlobalKey formKey; + final List formFields; + const MihForm({ + super.key, + required this.formKey, + required this.formFields, + }); + + @override + State createState() => _MihFormState(); +} + +class _MihFormState extends State { + @override + Widget build(BuildContext context) { + return Form( + key: widget.formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: widget.formFields, + ), + ); + } +} diff --git a/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart b/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart index dc44a614..69f47bbb 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_package_window.dart @@ -39,7 +39,7 @@ class _MihPackageWindowState extends State { setState(() { windowTitleSize = 25; horizontralWindowPadding = width / 7; - vertticalWindowPadding = 25; + vertticalWindowPadding = 10; windowWidth = width; windowHeight = height; }); 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 new file mode 100644 index 00000000..082f4ee0 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart @@ -0,0 +1,279 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:mzansi_innovation_hub/main.dart'; + +class MihTextFormField extends StatefulWidget { + final double? width; + final double? height; + final Color fillColor; + final Color inputColor; + final TextEditingController controller; + final bool? hasError; + final String hintText; + final double? borderRadius; + final bool? multiLineInput; + final bool? readOnly; + final bool? passwordMode; + final bool? numberMode; + final bool requiredText; + final FormFieldValidator? validator; + final List? autofillHints; + final double? elevation; + + const MihTextFormField({ + Key? key, + this.width, + this.height, + required this.fillColor, + required this.inputColor, + required this.controller, + this.hasError, + required this.hintText, + required this.requiredText, + this.borderRadius, + this.multiLineInput, + this.readOnly, + this.passwordMode, + this.numberMode, + this.validator, + this.autofillHints, + this.elevation, + }) : super(key: key); + + @override + State createState() => _MihTextFormFieldState(); +} + +class _MihTextFormFieldState extends State { + late bool _obscureText; + FormFieldState? _formFieldState; + + @override + void initState() { + super.initState(); + _obscureText = widget.passwordMode ?? false; + widget.controller.addListener(_onControllerTextChanged); + } + + @override + void didUpdateWidget(covariant MihTextFormField oldWidget) { + super.didUpdateWidget(oldWidget); + // If the controller itself changes, remove listener from old and add to new + if (widget.controller != oldWidget.controller) { + oldWidget.controller.removeListener(_onControllerTextChanged); + widget.controller.addListener(_onControllerTextChanged); + // Immediately update form field state if controller changed and has value + _formFieldState?.didChange(widget.controller.text); + } + } + + void _onControllerTextChanged() { + // Only update the FormField's value if it's not already the same + // and if the formFieldState is available. + if (_formFieldState != null && + _formFieldState!.value != widget.controller.text) { + _formFieldState!.didChange(widget.controller.text); + } + } + + @override + void dispose() { + widget.controller.removeListener(_onControllerTextChanged); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Center( + child: SizedBox( + width: widget.width, + height: widget.height, + child: Theme( + data: Theme.of(context).copyWith( + textSelectionTheme: TextSelectionThemeData( + selectionColor: widget.inputColor.withValues(alpha: 0.3), + selectionHandleColor: widget.inputColor, + ), + ), + 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, + style: TextStyle( + color: widget.fillColor, + 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, // <-- Add this line + children: [ + Material( + elevation: widget.elevation ?? 4.0, + borderRadius: + BorderRadius.circular(widget.borderRadius ?? 8.0), + child: SizedBox( + height: widget.height != null + ? widget.height! - 25 + : null, + child: TextFormField( + controller: widget.controller, + cursorColor: widget.inputColor, + autofillHints: widget.autofillHints, + textAlign: TextAlign.start, + textAlignVertical: widget.multiLineInput == true + ? TextAlignVertical.top + : TextAlignVertical.center, + obscureText: widget.passwordMode == true + ? _obscureText + : false, + expands: widget.passwordMode == true + ? false + : (widget.multiLineInput ?? false), + maxLines: widget.passwordMode == true ? 1 : null, + readOnly: widget.readOnly ?? false, + keyboardType: widget.numberMode == true + ? TextInputType.number + : null, + inputFormatters: widget.numberMode == true + ? [FilteringTextInputFormatter.digitsOnly] + : null, + style: TextStyle( + color: widget.inputColor, + fontWeight: FontWeight.w500, + ), + decoration: InputDecoration( + suffixIcon: widget.passwordMode == true + ? IconButton( + icon: Icon( + _obscureText + ? Icons.visibility_off + : Icons.visibility, + color: widget.inputColor, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }, + ) + : null, + errorStyle: const TextStyle( + height: 0, fontSize: 0), // <-- Add this line + contentPadding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 8.0), + filled: true, + fillColor: widget.fillColor, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: field.hasError + ? BorderSide( + color: MzanziInnovationHub.of(context)! + .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 + ? MzanziInnovationHub.of(context)! + .theme + .errorColor() + : widget.inputColor, + width: 3.0, + ), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: BorderSide( + color: MzanziInnovationHub.of(context)! + .theme + .errorColor(), + width: 3.0, + ), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular( + widget.borderRadius ?? 8.0), + borderSide: BorderSide( + color: MzanziInnovationHub.of(context)! + .theme + .errorColor(), + width: 3.0, + ), + ), + ), + onChanged: (value) { + field.didChange(value); + }, + ), + ), + ), + if (field.hasError) + Row( + children: [ + Padding( + padding: + const EdgeInsets.only(left: 8.0, top: 4.0), + child: Text( + field.errorText ?? '', + style: TextStyle( + fontSize: 12, + color: MzanziInnovationHub.of(context)! + .theme + .errorColor(), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ], + ); + }, + ), + ], + ), + ), + ), + ); + } +} diff --git a/Frontend/lib/mih_env/env.dart b/Frontend/lib/mih_env/env.dart index c96e44e0..903bcfe5 100644 --- a/Frontend/lib/mih_env/env.dart +++ b/Frontend/lib/mih_env/env.dart @@ -15,16 +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"; - whatsappAccessToken = - "EAAPINXuNFdYBOzBjTcvZA2iPXEHbHRF9uNXyP3ihkPRUcBqKNru5g9NKRRKkFaiaITEzO3BMo6CjdUmlDH4qYTW2mzDrZB4Q21ZCEZBgECZCu27vfaOXJZCYQLNxwoXkrZBRYv8ZAP37f69r3z9JxLQxdxn9gwqA3oNZAlBBRapJQzxOr6pZBTdI3bbjbu17ZBIwRcF4JCqPDCNLEZCI3bmHwEd2i2niNMYZD"; - //fingerPrintPluginKey = 'h5X7a5j14iUZCobI1ZeX'; + baseApiUrl = "http://localhost:8080"; + baseFileUrl = "http://localhost:9000"; + baseAiUrl = "http://localhost:11434"; break; } case Enviroment.prod: diff --git a/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart b/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart index f5aa2597..ed6409d8 100644 --- a/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart +++ b/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart @@ -1,5 +1,6 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_install_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_tile.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; @@ -9,7 +10,6 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.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:universal_html/js.dart" as js; import 'package:url_launcher/url_launcher.dart'; import 'package:share_plus/share_plus.dart'; @@ -41,46 +41,6 @@ class _MihInfoState extends State { final Uri _redditUrl = Uri.parse('https://www.reddit.com/r/Mzani_Innovation_Hub/'); - void installMihTrigger() { - final isWebAndroid = - kIsWeb && (defaultTargetPlatform == TargetPlatform.android); - final isWebIos = kIsWeb && (defaultTargetPlatform == TargetPlatform.iOS); - - if (isWebAndroid) { - launchSocialUrl( - Uri.parse( - "https://play.google.com/store/apps/details?id=za.co.mzansiinnovationhub.mih", - ), - ); - } else if (isWebIos) { - //Show pop up for IOS - // _showIOSInstallationGuide(); - launchSocialUrl( - Uri.parse( - "https://apps.apple.com/za/app/mzansi-innovation-hub/id6743310890", - ), - ); - } else if (MzanziInnovationHub.of(context)!.theme.getPlatform() == - "Android") { - //Installed Android App - // _showIOSInstallationGuide(); - launchSocialUrl( - Uri.parse( - "https://play.google.com/store/apps/details?id=za.co.mzansiinnovationhub.mih", - ), - ); - } else if (MzanziInnovationHub.of(context)!.theme.getPlatform() == "iOS") { - launchSocialUrl( - Uri.parse( - "https://apps.apple.com/za/app/mzansi-innovation-hub/id6743310890", - ), - ); - } else { - //Web - js.context.callMethod("presentAddToHome"); - } - } - Widget founderBio() { String bio = ""; bio += "BSc Computer Science & Information Systems\n"; @@ -553,7 +513,7 @@ class _MihInfoState extends State { children: [ MihButton( onPressed: () { - installMihTrigger(); + MihInstallServices().installMihTrigger(context); }, buttonColor: MzanziInnovationHub.of(context)! .theme diff --git a/Frontend/lib/mih_packages/authentication/forgot_password.dart b/Frontend/lib/mih_packages/authentication/forgot_password.dart index 0b267854..f9705008 100644 --- a/Frontend/lib/mih_packages/authentication/forgot_password.dart +++ b/Frontend/lib/mih_packages/authentication/forgot_password.dart @@ -2,11 +2,14 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.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_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import '../../main.dart'; import 'package:supertokens_flutter/http.dart' as http; -import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart'; import '../../mih_components/mih_layout/mih_action.dart'; import '../../mih_components/mih_layout/mih_body.dart'; import '../../mih_components/mih_layout/mih_header.dart'; @@ -25,6 +28,7 @@ class ForgotPassword extends StatefulWidget { class _ForgotPasswordState extends State { final emailController = TextEditingController(); + final _formKey = GlobalKey(); //bool _obscureText = true; bool successfulForgotPassword = false; @@ -201,7 +205,7 @@ class _ForgotPasswordState extends State { ); } - MIHBody getBody() { + MIHBody getBody(double width) { return MIHBody( borderOn: false, bodyItems: [ @@ -219,7 +223,12 @@ class _ForgotPasswordState extends State { child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Padding( - padding: const EdgeInsets.all(25.0), + padding: MzanziInnovationHub.of(context)!.theme.screenType == + "desktop" + ? EdgeInsets.symmetric( + vertical: 25, horizontal: width * 0.2) + : EdgeInsets.symmetric( + vertical: 25, horizontal: width * 0.075), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -244,40 +253,56 @@ class _ForgotPasswordState extends State { .secondaryColor(), ), ), - //spacer const SizedBox(height: 25), - - //email input - SizedBox( - width: 500.0, - child: MIHTextField( - controller: emailController, - hintText: 'Email', - editable: true, - required: true, - ), - ), - - //spacer - const SizedBox(height: 25), - MihButton( - onPressed: () { - prePassResteWarning(); - }, - buttonColor: MzanziInnovationHub.of(context)! - .theme - .secondaryColor(), - width: 300, - child: Text( - "Reset Password", - style: TextStyle( - color: MzanziInnovationHub.of(context)! + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! .theme .primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + controller: emailController, + multiLineInput: false, + requiredText: true, + hintText: "Email", + validator: (value) { + return MihValidationServices() + .validateEmail(value); + }, ), - ), + //spacer + const SizedBox(height: 20), + Align( + alignment: Alignment.center, + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + prePassResteWarning(); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 300, + child: Text( + "Reset Password", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), ], ), @@ -304,11 +329,12 @@ class _ForgotPasswordState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MIHLayoutBuilder( actionButton: getActionButton(), header: getHeader(), secondaryActionButton: null, - body: getBody(), + body: getBody(screenWidth), actionDrawer: null, secondaryActionDrawer: null, bottomNavBar: null, diff --git a/Frontend/lib/mih_packages/authentication/register.dart b/Frontend/lib/mih_packages/authentication/register.dart index 229bc938..57adeeb6 100644 --- a/Frontend/lib/mih_packages/authentication/register.dart +++ b/Frontend/lib/mih_packages/authentication/register.dart @@ -1,18 +1,18 @@ import 'dart:convert'; +import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_install_services.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_form.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_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../main.dart'; -//import '../objects/sessionST.dart'; -//import 'package:supertokens_flutter/supertokens.dart'; import 'package:supertokens_flutter/http.dart' as http; import 'package:supertokens_flutter/supertokens.dart'; - -import '../../mih_components/mih_inputs_and_buttons/mih_pass_input.dart'; -import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart'; import '../../mih_components/mih_layout/mih_action.dart'; import '../../mih_components/mih_layout/mih_body.dart'; import '../../mih_components/mih_layout/mih_header.dart'; @@ -37,6 +37,7 @@ class _RegisterState extends State { final officeID = TextEditingController(); final baseAPI = AppEnviroment.baseApiUrl; final FocusNode _focusNode = FocusNode(); + final _formKey = GlobalKey(); bool _obscureText = true; bool successfulSignUp = false; @@ -218,19 +219,8 @@ class _RegisterState extends State { ); } - void validateInput() async { - if (emailController.text.isEmpty || - passwordController.text.isEmpty || - confirmPasswordController.text.isEmpty) { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } else { - await signUserUp(); - } + void submitFormInput() async { + await signUserUp(); } void toggle() { @@ -247,14 +237,11 @@ class _RegisterState extends State { padding: const EdgeInsets.all(10.0), child: MihButton( onPressed: () { - Navigator.of(context).pushNamed( - '/about', - arguments: 0, - ); + MihInstallServices().installMihTrigger(context); }, buttonColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, + width: 150, child: Text( "Install MIH", style: TextStyle( @@ -267,10 +254,7 @@ class _RegisterState extends State { ), iconSize: 35, onTap: () { - Navigator.of(context).pushNamed( - '/about', - arguments: 0, - ); + MihInstallServices().installMihTrigger(context); }, ), ); @@ -315,7 +299,7 @@ class _RegisterState extends State { ); } - MIHBody getBody() { + MIHBody getBody(double width) { return MIHBody( borderOn: false, bodyItems: [ @@ -325,7 +309,11 @@ class _RegisterState extends State { onKeyEvent: (event) async { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.enter) { - validateInput(); + if (_formKey.currentState!.validate()) { + submitFormInput(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } } }, child: SafeArea( @@ -333,7 +321,10 @@ class _RegisterState extends State { child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Padding( - padding: const EdgeInsets.all(25.0), + padding: MzanziInnovationHub.of(context)!.theme.screenType == + "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -359,93 +350,125 @@ class _RegisterState extends State { ), ), //spacer - const SizedBox(height: 25), - //email input - SizedBox( - width: 500.0, - child: MIHTextField( - controller: emailController, - hintText: 'Email', - editable: true, - required: true, - ), - ), - //spacer - const SizedBox(height: 10), - //password input - SizedBox( - width: 500.0, - child: MIHPassField( - controller: passwordController, - hintText: 'Password', - required: true, - signIn: false, - ), - ), - //spacer - const SizedBox(height: 10), - //password input - SizedBox( - width: 500.0, - child: MIHPassField( - controller: confirmPasswordController, - hintText: 'Confirm Password', - required: true, - signIn: false, - ), - ), - //spacer - const SizedBox(height: 25), - // sign up button - MihButton( - onPressed: () { - validateInput(); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.successColor(), - width: 300, - child: Text( - "Create New Account", - style: TextStyle( - color: MzanziInnovationHub.of(context)! + // const SizedBox(height: 20), + MihForm( + formKey: _formKey, + formFields: [ + //email input + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! .theme .primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + controller: emailController, + multiLineInput: false, + requiredText: true, + hintText: "Email", + autofillHints: const [AutofillHints.email], + validator: (value) { + return MihValidationServices().validateEmail(value); + }, ), - ), - ), - - const SizedBox(height: 10), - //register text - SizedBox( - width: 500.0, - //height: 100.0, - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - const Text( - 'Already a User?', - style: TextStyle(fontSize: 18, color: Colors.grey), - ), - const SizedBox( - width: 6, - ), - GestureDetector( - onTap: widget.onTap, - child: Text( - 'Sign In', - style: TextStyle( - fontSize: 18, - color: MzanziInnovationHub.of(context)! + //spacer + const SizedBox(height: 10), + //password input + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: passwordController, + multiLineInput: false, + requiredText: true, + hintText: "Password", + passwordMode: true, + autofillHints: const [AutofillHints.password], + validator: (value) { + return MihValidationServices() + .validatePassword(value); + }, + ), + //spacer + const SizedBox(height: 10), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: confirmPasswordController, + multiLineInput: false, + requiredText: true, + hintText: "Confirm Password", + passwordMode: true, + autofillHints: const [AutofillHints.password], + validator: (value) { + return MihValidationServices() + .validatePassword(value); + }, + ), + //spacer + const SizedBox(height: 20), + // sign up button + Center( + child: Wrap( + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitFormInput(); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .successColor(), + width: 300, + child: Text( + "Create New Account", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + MihButton( + onPressed: widget.onTap, + buttonColor: MzanziInnovationHub.of(context)! .theme .secondaryColor(), - fontWeight: FontWeight.bold, + width: 300, + child: Text( + "I have an account", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), ), - ), - ) - ], - ), + ], + ), + ), + + //here + ], ) ], ), @@ -468,11 +491,12 @@ class _RegisterState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MIHLayoutBuilder( actionButton: getActionButton(), header: getHeader(), secondaryActionButton: getSecondaryActionButton(), - body: getBody(), + body: getBody(screenWidth), actionDrawer: null, secondaryActionDrawer: null, bottomNavBar: null, diff --git a/Frontend/lib/mih_packages/authentication/reset_password.dart b/Frontend/lib/mih_packages/authentication/reset_password.dart index d12f8ef7..a4ed515b 100644 --- a/Frontend/lib/mih_packages/authentication/reset_password.dart +++ b/Frontend/lib/mih_packages/authentication/reset_password.dart @@ -2,10 +2,13 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.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_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 '../../main.dart'; import 'package:supertokens_flutter/http.dart' as http; -import '../../mih_components/mih_inputs_and_buttons/mih_pass_input.dart'; import '../../mih_components/mih_layout/mih_action.dart'; import '../../mih_components/mih_layout/mih_body.dart'; import '../../mih_components/mih_layout/mih_header.dart'; @@ -35,6 +38,7 @@ class _ResetPasswordState extends State { bool acceptWarning = false; // focus node to capture keyboard events final FocusNode _focusNode = FocusNode(); + final _formKey = GlobalKey(); final baseAPI = AppEnviroment.baseApiUrl; @@ -131,16 +135,8 @@ class _ResetPasswordState extends State { ); } - void validateInput() async { - if (passwordController.text.isEmpty || - confirmPasswordController.text.isEmpty) { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } else if (passwordController.text != confirmPasswordController.text) { + void submitFormInput() async { + if (passwordController.text != confirmPasswordController.text) { passwordError(); } else { await submitPasswodReset(); @@ -185,7 +181,7 @@ class _ResetPasswordState extends State { ); } - MIHBody getBody() { + MIHBody getBody(double width) { return MIHBody( borderOn: false, bodyItems: [ @@ -195,7 +191,11 @@ class _ResetPasswordState extends State { onKeyEvent: (event) async { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.enter) { - validateInput(); + if (_formKey.currentState!.validate()) { + submitFormInput(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } } }, child: SafeArea( @@ -203,7 +203,10 @@ class _ResetPasswordState extends State { child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Padding( - padding: const EdgeInsets.all(25.0), + padding: MzanziInnovationHub.of(context)!.theme.screenType == + "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -229,63 +232,102 @@ class _ResetPasswordState extends State { ), ), //spacer - // const SizedBox(height: 15), - // Text( - // 'token: ${widget.token}', - // style: TextStyle( - // fontSize: 15, - // fontWeight: FontWeight.bold, - // color: MzanziInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // ), - // ), - //spacer const SizedBox(height: 25), - //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 - MihButton( - onPressed: () { - validateInput(); - }, - buttonColor: MzanziInnovationHub.of(context)! - .theme - .secondaryColor(), - width: 300, - child: Text( - "Reset Password", - style: TextStyle( - color: MzanziInnovationHub.of(context)! + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! .theme .primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + controller: passwordController, + multiLineInput: false, + requiredText: true, + hintText: "Password", + passwordMode: true, + autofillHints: const [AutofillHints.password], + validator: (value) { + return MihValidationServices() + .validatePassword(value); + }, ), - ), + //spacer + const SizedBox(height: 10), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: confirmPasswordController, + multiLineInput: false, + requiredText: true, + hintText: "Confirm Password", + passwordMode: true, + autofillHints: const [AutofillHints.password], + validator: (value) { + return MihValidationServices() + .validatePassword(value); + }, + ), + + // //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 + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitFormInput(); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 300, + child: Text( + "Reset Password", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), ], ), @@ -313,11 +355,12 @@ class _ResetPasswordState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MIHLayoutBuilder( actionButton: getActionButton(), header: getHeader(), secondaryActionButton: null, - body: getBody(), + body: getBody(screenWidth), actionDrawer: null, secondaryActionDrawer: null, bottomNavBar: null, diff --git a/Frontend/lib/mih_packages/authentication/signin.dart b/Frontend/lib/mih_packages/authentication/signin.dart index 85d01399..1f17a7c3 100644 --- a/Frontend/lib/mih_packages/authentication/signin.dart +++ b/Frontend/lib/mih_packages/authentication/signin.dart @@ -1,13 +1,16 @@ import 'dart:convert'; +import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_install_services.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_form.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_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../main.dart'; import 'package:supertokens_flutter/http.dart' as http; -import '../../mih_components/mih_inputs_and_buttons/mih_pass_input.dart'; -import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart'; import '../../mih_components/mih_layout/mih_action.dart'; import '../../mih_components/mih_layout/mih_body.dart'; import '../../mih_components/mih_layout/mih_header.dart'; @@ -34,6 +37,7 @@ class _SignInState extends State { // focus node to capture keyboard events final FocusNode _focusNode = FocusNode(); + final _formKey = GlobalKey(); final baseAPI = AppEnviroment.baseApiUrl; @@ -99,7 +103,11 @@ class _SignInState extends State { emailController.text = "testpatient@mzansi-innovation-hub.co.za"; passwordController.text = "Testprofile@1234"; }); - validateInput(); + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } }, tileName: "Patient", tileIcon: Icon( @@ -116,7 +124,11 @@ class _SignInState extends State { emailController.text = "testdoctor@mzansi-innovation-hub.co.za"; passwordController.text = "Testprofile@1234"; }); - validateInput(); + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } }, tileName: "Doctor", tileIcon: Icon( @@ -134,7 +146,11 @@ class _SignInState extends State { emailController.text = "test-business@mzansi-innovation-hub.co.za"; passwordController.text = "Testprofile@1234"; }); - validateInput(); + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } }, tileName: "Business", tileIcon: Icon( @@ -151,7 +167,11 @@ class _SignInState extends State { emailController.text = "test@mzansi-innovation-hub.co.za"; passwordController.text = "Testprofile@1234"; }); - validateInput(); + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } }, tileName: "Test", tileIcon: Icon( @@ -174,27 +194,17 @@ class _SignInState extends State { ); } - void validateInput() async { - if (emailController.text.isEmpty || passwordController.text.isEmpty) { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, + void submitSignInForm() async { + await signUserIn(); + if (successfulSignIn) { + Navigator.of(context).pushNamedAndRemoveUntil( + '/', + (route) => false, + arguments: AuthArguments( + true, + true, + ), ); - } else { - await signUserIn(); - if (successfulSignIn) { - // TextInput.finishAutofillContext(); - Navigator.of(context).pushNamedAndRemoveUntil( - '/', - (route) => false, - arguments: AuthArguments( - true, - true, - ), - ); - } } } @@ -293,14 +303,11 @@ class _SignInState extends State { padding: const EdgeInsets.all(10.0), child: MihButton( onPressed: () { - Navigator.of(context).pushNamed( - '/about', - arguments: 0, - ); + MihInstallServices().installMihTrigger(context); }, buttonColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, + width: 150, child: Text( "Install MIH", style: TextStyle( @@ -361,7 +368,7 @@ class _SignInState extends State { ); } - MIHBody getBody() { + MIHBody getBody(double width) { return MIHBody( borderOn: false, bodyItems: [ @@ -371,7 +378,11 @@ class _SignInState extends State { onKeyEvent: (event) async { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.enter) { - validateInput(); + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } } }, child: SafeArea( @@ -379,7 +390,10 @@ class _SignInState extends State { child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Padding( - padding: const EdgeInsets.all(25.0), + padding: MzanziInnovationHub.of(context)!.theme.screenType == + "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), child: AutofillGroup( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -405,243 +419,223 @@ class _SignInState extends State { .secondaryColor(), ), ), - //spacer - const SizedBox(height: 25), - - // SizedBox( - // width: 500.0, - // //height: 100.0, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.start, - // children: [ - // GestureDetector( - // onTap: () { - // showSandboxProfiles(); - // }, - // child: Text( - // 'Sandbox Profile', - // style: TextStyle( - // fontSize: 18, - // color: MzanziInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // ], - // ), - // ), - // const SizedBox(height: 10), - //email input - SizedBox( - width: 500.0, - child: MIHTextField( - controller: emailController, - hintText: 'Email', - editable: true, - required: true, - autoFillHintGroup: const [AutofillHints.email], - textInputAction: TextInputAction.next, - ), - ), - //spacer const SizedBox(height: 10), - //password input - SizedBox( - width: 500.0, - child: MIHPassField( - controller: passwordController, - hintText: 'Password', - required: true, - signIn: true, - autoFillHintGroup: const [AutofillHints.password], - ), - ), - SizedBox( - width: 500.0, - //height: 100.0, - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - GestureDetector( - onTap: () { - Navigator.of(context).pushNamed( - '/forgot-password', - ); - }, - child: Text( - 'Forgot Password?', - style: TextStyle( - fontSize: 15, - color: MzanziInnovationHub.of(context)! - .theme - .secondaryColor(), - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ), - - //spacer - const SizedBox(height: 30), - // sign in button - MihButton( - onPressed: () { - validateInput(); - }, - buttonColor: MzanziInnovationHub.of(context)! - .theme - .secondaryColor(), - width: 300, - child: Text( - "Sign In", - style: TextStyle( - color: MzanziInnovationHub.of(context)! + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! .theme .primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + controller: emailController, + multiLineInput: false, + requiredText: true, + hintText: "Email", + autofillHints: const [AutofillHints.email], + validator: (value) { + return MihValidationServices() + .validateEmail(value); + }, ), - ), - ), - const SizedBox(height: 10), - MihButton( - onPressed: widget.onTap, - buttonColor: MzanziInnovationHub.of(context)! - .theme - .successColor(), - width: 300, - child: Text( - "Create New Account", - style: TextStyle( - color: MzanziInnovationHub.of(context)! + //spacer + const SizedBox(height: 10), + //password input + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! .theme .primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + controller: passwordController, + multiLineInput: false, + requiredText: true, + hintText: "Password", + passwordMode: true, + autofillHints: const [AutofillHints.password], + validator: (value) { + return MihValidationServices() + .validatePassword(value); + }, ), - ), - ), - //spacer - const SizedBox(height: 10), - //register text - // SizedBox( - // width: 500.0, - // //height: 100.0, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.end, - // children: [ - // Text( - // 'New User?', - // style: TextStyle( - // fontSize: 18, - // color: MzanziInnovationHub.of(context)! - // .theme - // .messageTextColor()), - // ), - // const SizedBox( - // width: 6, - // ), - // GestureDetector( - // onTap: widget.onTap, - // child: Text( - // 'Register Now', - // style: TextStyle( - // fontSize: 18, - // color: MzanziInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // ], - // ), - // ), - //spacer - const SizedBox(height: 15), - SizedBox( - width: 500.0, - //height: 100.0, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Flexible( - flex: 1, - child: Padding( - padding: EdgeInsets.only(right: 10.0), - child: Divider(), - ), - ), - Flexible( - flex: 1, - child: GestureDetector( - child: Text( - 'Use Sandox Profile', - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, + const SizedBox(height: 10), + SizedBox( + // width: 500.0, + //height: 100.0, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + onTap: () { + Navigator.of(context).pushNamed( + '/forgot-password', + ); + }, + child: Text( + 'Forgot Password?', + style: TextStyle( fontSize: 15, color: MzanziInnovationHub.of(context)! .theme - .secondaryColor()), + .secondaryColor(), + fontWeight: FontWeight.bold, + ), + ), ), - onTap: () { - setState(() { - showProfiles = !showProfiles; - }); - }, - ), + ], ), - const Flexible( - flex: 1, - child: Padding( - padding: EdgeInsets.only(left: 10.0), - child: Divider(), - ), - ), - ], - ), - ), - const SizedBox(height: 10), - Visibility( - visible: showProfiles, - child: SizedBox( - width: 500, - child: Column( - //mainAxisSize: MainAxisSize.max, - children: [ - GridView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: sandboxProfileList.length, - gridDelegate: - const SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 10, - maxCrossAxisExtent: 100), - itemBuilder: (context, index) { - return sandboxProfileList[index]; - }, - ), - const SizedBox(height: 20), - Text( - "NB: These accounts are used for test purposes. Please do not store personal information on these profiles.", - textAlign: TextAlign.center, - style: TextStyle( - color: MzanziInnovationHub.of(context)! - .theme - .secondaryColor(), - fontSize: 15.0, - fontWeight: FontWeight.bold, - ), - ), - ], ), - ), + + //spacer + const SizedBox(height: 20), + // sign in button + Center( + child: Wrap( + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: + MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 300, + child: Text( + "Sign In", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + MihButton( + onPressed: widget.onTap, + buttonColor: + MzanziInnovationHub.of(context)! + .theme + .successColor(), + width: 300, + child: Text( + "Create New Account", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ), + + //spacer + const SizedBox(height: 35), + Center( + child: SizedBox( + width: width, + //height: 100.0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Flexible( + flex: 1, + child: Padding( + padding: EdgeInsets.only(right: 10.0), + child: Divider(), + ), + ), + Flexible( + flex: 1, + child: GestureDetector( + child: Text( + 'Use Sandox Profile', + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + color: MzanziInnovationHub.of( + context)! + .theme + .secondaryColor()), + ), + onTap: () { + setState(() { + showProfiles = !showProfiles; + }); + }, + ), + ), + const Flexible( + flex: 1, + child: Padding( + padding: EdgeInsets.only(left: 10.0), + child: Divider(), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 10), + Center( + child: Visibility( + visible: showProfiles, + child: SizedBox( + width: 500, + child: Column( + //mainAxisSize: MainAxisSize.max, + children: [ + GridView.builder( + physics: + const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: sandboxProfileList.length, + gridDelegate: + const SliverGridDelegateWithMaxCrossAxisExtent( + mainAxisSpacing: 10, + maxCrossAxisExtent: 100), + itemBuilder: (context, index) { + return sandboxProfileList[index]; + }, + ), + const SizedBox(height: 20), + Text( + "NB: These accounts are used for test purposes. Please do not store personal information on these profiles.", + textAlign: TextAlign.center, + style: TextStyle( + color: + MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + fontSize: 15.0, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ), + ), + ], ), ], ), @@ -674,11 +668,12 @@ class _SignInState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MIHLayoutBuilder( actionButton: getActionButton(), header: getHeader(), secondaryActionButton: getSecondaryActionButton(), - body: getBody(), + body: getBody(screenWidth), actionDrawer: null, secondaryActionDrawer: null, bottomNavBar: null, 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 63070957..8b1abed4 100644 --- a/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart +++ b/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart @@ -1,12 +1,14 @@ 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_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_multiline_text_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_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_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_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'; @@ -57,6 +59,7 @@ class _BuildAppointmentListState extends State { TextEditingController fnameController = TextEditingController(); TextEditingController lnameController = TextEditingController(); TextEditingController daysExtensionController = TextEditingController(); + final _formKey = GlobalKey(); int counter = 0; late double width; late double height; @@ -69,7 +72,7 @@ class _BuildAppointmentListState extends State { } } - Widget displayAppointment(int index) { + Widget displayAppointment(int index, double bodyWidth) { String heading = "${widget.appointmentList[index].date_time.split('T')[1].substring(0, 5)} - ${widget.appointmentList[index].title.toUpperCase()}"; String description = widget.appointmentList[index].description; @@ -100,54 +103,50 @@ class _BuildAppointmentListState extends State { MzanziInnovationHub.of(context)!.theme.messageTextColor(); } - return Padding( - padding: const EdgeInsets.all(5.0), - child: Container( - decoration: BoxDecoration( - border: Border.all( - width: 3.0, - color: appointmentColor, - ), - borderRadius: BorderRadius.circular(20)), - child: ListTile( - title: Text( - heading, - style: TextStyle( - color: appointmentColor, - fontWeight: FontWeight.bold, - ), + return Container( + decoration: BoxDecoration( + border: Border.all( + width: 3.0, + color: appointmentColor, ), - subtitle: Text( - description, - style: TextStyle( - color: appointmentColor, - overflow: TextOverflow.ellipsis, - ), + borderRadius: BorderRadius.circular(20)), + child: ListTile( + title: Text( + heading, + style: TextStyle( + color: appointmentColor, + fontWeight: FontWeight.bold, ), - onTap: () { - setState(() { - widget.titleController.text = widget.appointmentList[index].title; - widget.descriptionIDController.text = - widget.appointmentList[index].description; - widget.dateController.text = - widget.appointmentList[index].date_time.split('T')[0]; - widget.timeController.text = widget - .appointmentList[index].date_time - .split('T')[1] - .substring(0, 5); - }); - if (widget.inWaitingRoom == false) { - appointmentDetailsWindow(index); - } else { - waitingRiinAppointmentDetailsWindow(index); - } - }, ), + subtitle: Text( + description, + style: TextStyle( + color: appointmentColor, + overflow: TextOverflow.ellipsis, + ), + ), + onTap: () { + setState(() { + widget.titleController.text = widget.appointmentList[index].title; + widget.descriptionIDController.text = + widget.appointmentList[index].description; + widget.dateController.text = + widget.appointmentList[index].date_time.split('T')[0]; + widget.timeController.text = widget.appointmentList[index].date_time + .split('T')[1] + .substring(0, 5); + }); + if (widget.inWaitingRoom == false) { + appointmentDetailsWindow(index, bodyWidth); + } else { + waitingRiinAppointmentDetailsWindow(index, bodyWidth); + } + }, ), ); } - void appointmentDetailsWindow(int index) { + void appointmentDetailsWindow(int index, double bodyWidth) { showDialog( context: context, barrierDismissible: false, @@ -171,7 +170,7 @@ class _BuildAppointmentListState extends State { backgroundColor: MzanziInnovationHub.of(context)!.theme.successColor(), onTap: () { - appointmentUpdateWindow(index); + appointmentUpdateWindow(index, bodyWidth); }, ), SpeedDialChild( @@ -200,56 +199,72 @@ class _BuildAppointmentListState extends State { widget.titleController.clear(); widget.descriptionIDController.clear(); }, - windowBody: Column( - children: [ - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTextField( + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: widget.titleController, - hintText: "Title", - editable: false, - required: false, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Appointment Title", ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTextField( - controller: widget.dateController, - hintText: "Date", - editable: false, - required: false, - )), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTextField( - controller: widget.timeController, - hintText: "Time", - editable: false, - required: false, - )), - const SizedBox(height: 10), - SizedBox( - // width: 500, - height: 250, - child: MIHMLTextField( + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: widget.dateController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Date", + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: widget.timeController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Time", + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: widget.descriptionIDController, - hintText: "Description", - editable: false, - required: false, + multiLineInput: true, + height: 250, + requiredText: true, + readOnly: true, + hintText: "Appointment Description", ), - ), - const SizedBox(height: 10), - ], + const SizedBox(height: 10), + ], + ), ), ); }, ); } - void waitingRiinAppointmentDetailsWindow(int index) { + void waitingRiinAppointmentDetailsWindow(int index, double bodyWidth) { showDialog( context: context, barrierDismissible: false, @@ -273,7 +288,7 @@ class _BuildAppointmentListState extends State { backgroundColor: MzanziInnovationHub.of(context)!.theme.successColor(), onTap: () { - appointmentUpdateWindow(index); + appointmentUpdateWindow(index, bodyWidth); }, ), SpeedDialChild( @@ -302,65 +317,82 @@ class _BuildAppointmentListState extends State { widget.titleController.clear(); widget.descriptionIDController.clear(); }, - windowBody: Column( - children: [ - SizedBox( - // width: 500, - child: MIHTextField( + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: widget.titleController, - hintText: "Title", - editable: false, - required: false, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Appointment Title", ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTextField( - controller: widget.titleController, - hintText: "Patient ID Number", - editable: false, - required: false, + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: widget.dateController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Date", ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTextField( - controller: widget.dateController, - hintText: "Date", - editable: false, - required: false, - )), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTextField( - controller: widget.timeController, - hintText: "Time", - editable: false, - required: false, - )), - const SizedBox(height: 10), - SizedBox( - // width: 500, - height: 250, - child: MIHMLTextField( + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: widget.timeController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Time", + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: widget.descriptionIDController, - hintText: "Description", - editable: false, - required: false, + multiLineInput: true, + height: 250, + requiredText: true, + readOnly: true, + hintText: "Appointment Description", ), - ), - const SizedBox(height: 20), - ], + const SizedBox(height: 10), + // SizedBox( + // // width: 500, + // child: MIHTextField( + // controller: widget.titleController, + // hintText: "Patient ID Number", + // editable: false, + // required: false, + // ), + // ), + // const SizedBox(height: 10), + ], + ), ), ); }, ); } - void appointmentUpdateWindow(int index) { + void appointmentUpdateWindow(int index, double bodyWidth) { showDialog( context: context, barrierDismissible: false, @@ -382,73 +414,102 @@ class _BuildAppointmentListState extends State { }); Navigator.of(context).pop(); }, - windowBody: Column( - children: [ - SizedBox( - // width: 500, - child: MIHTextField( - controller: widget.titleController, - hintText: "Title", - editable: true, - required: true, - ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHDateField( - controller: widget.dateController, - lableText: "Date", - required: true, - ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTimeField( - controller: widget.timeController, - lableText: "Time", - required: true, - ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - height: 250, - child: MIHMLTextField( - controller: widget.descriptionIDController, - hintText: "Description", - editable: true, - required: true, - ), - ), - const SizedBox(height: 20), - Wrap( - alignment: WrapAlignment.center, - runSpacing: 10, - spacing: 10, - children: [ - MihButton( - onPressed: () { - updateAppointmentCall(index); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.successColor(), - width: 300, - child: Text( - "Update", - 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( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: widget.titleController, + multiLineInput: false, + requiredText: true, + hintText: "Appointment Title", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + SizedBox( + // width: 500, + child: MIHDateField( + controller: widget.dateController, + lableText: "Date", + required: true, ), ), - ), - ], - ) - ], + const SizedBox(height: 10), + SizedBox( + // width: 500, + child: MIHTimeField( + controller: widget.timeController, + lableText: "Time", + required: true, + ), + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: widget.descriptionIDController, + multiLineInput: true, + height: 250, + requiredText: true, + hintText: "Appointment Description", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 20), + Center( + child: Wrap( + alignment: WrapAlignment.center, + runSpacing: 10, + spacing: 10, + children: [ + MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + updateAppointmentCall(index); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .successColor(), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ), + ], + ), + ], + ), ), ); }, @@ -456,9 +517,7 @@ class _BuildAppointmentListState extends State { } bool isAppointmentInputValid() { - if (widget.titleController.text.isEmpty || - widget.descriptionIDController.text.isEmpty || - widget.dateController.text.isEmpty || + if (widget.dateController.text.isEmpty || widget.timeController.text.isEmpty) { return false; } else { @@ -585,7 +644,7 @@ class _BuildAppointmentListState extends State { shrinkWrap: true, itemCount: widget.appointmentList.length, itemBuilder: (context, index) { - return displayAppointment(index); + return displayAppointment(index, width); }, ), ); diff --git a/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart b/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart index abf7f20b..f443d574 100644 --- a/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart +++ b/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart @@ -1,14 +1,16 @@ 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_multiline_text_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_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_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_objects/appointment.dart'; import 'package:mzansi_innovation_hub/mih_objects/business.dart'; @@ -59,6 +61,8 @@ class _PatientAccessRequestState extends State { late Future> businessAppointmentResults; late Future> appointmentResults; + final _formKey = GlobalKey(); + Widget displayAppointmentList(List appointmentList) { if (appointmentList.isNotEmpty) { return Expanded( @@ -96,7 +100,7 @@ class _PatientAccessRequestState extends State { ); } - void addAppointmentWindow() { + void addAppointmentWindow(double width) { showDialog( context: context, barrierDismissible: false, @@ -111,65 +115,94 @@ class _PatientAccessRequestState extends State { _appointmentTitleController.clear(); _appointmentDescriptionIDController.clear(); }, - windowBody: Column( - children: [ - SizedBox( - // width: 500, - child: MIHTextField( - controller: _appointmentTitleController, - hintText: "Title", - editable: true, - required: true, + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _appointmentTitleController, + multiLineInput: false, + requiredText: true, + hintText: "Appointment Title", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + SizedBox( + // width: 500, + child: MIHDateField( + controller: _appointmentDateController, + lableText: "Date", + required: true, + ), + ), + const SizedBox(height: 10), + SizedBox( + // width: 500, + child: MIHTimeField( + controller: _appointmentTimeController, + lableText: "Time", + required: true, + ), + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _appointmentDescriptionIDController, + multiLineInput: true, + height: 250, + requiredText: true, + hintText: "Appointment Description", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 20), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + addAppointmentCall(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .successColor(), + width: 300, + child: Text( + "Add", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHDateField( - controller: _appointmentDateController, - lableText: "Date", - required: true, - ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTimeField( - controller: _appointmentTimeController, - lableText: "Time", - required: true, - ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - height: 250, - child: MIHMLTextField( - controller: _appointmentDescriptionIDController, - hintText: "Description", - editable: true, - required: true, - ), - ), - const SizedBox(height: 20), - MihButton( - onPressed: () { - addAppointmentCall(); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.successColor(), - width: 300, - child: Text( - "Add", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ], + ], + ), ), ); }, @@ -247,7 +280,7 @@ class _PatientAccessRequestState extends State { }); } - Widget getBody() { + Widget getBody(double width) { return Stack( children: [ MihSingleChildScroll( @@ -320,7 +353,7 @@ class _PatientAccessRequestState extends State { backgroundColor: MzanziInnovationHub.of(context)!.theme.successColor(), onTap: () { - addAppointmentWindow(); + addAppointmentWindow(width); }, ) ], @@ -362,9 +395,10 @@ class _PatientAccessRequestState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MihPackageToolBody( borderOn: false, - bodyItem: getBody(), + bodyItem: getBody(screenWidth), ); } } 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 96f7c2fe..669ba269 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart @@ -4,10 +4,10 @@ import 'dart:convert'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.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_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'; @@ -436,6 +436,7 @@ class _AiChatState extends State { const SizedBox(height: 15), Row( mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, children: [ IconButton.filled( onPressed: () { @@ -450,14 +451,19 @@ class _AiChatState extends State { ), ), const SizedBox(width: 10), - SizedBox( + MihTextFormField( width: 200, - child: MIHTextField( - controller: _fontSizeController, - hintText: "Chat Font Size", - editable: false, - required: true, - ), + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: _fontSizeController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Time", ), const SizedBox(width: 10), IconButton.filled( 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 ee7cd38d..8f907457 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 @@ -2,10 +2,12 @@ 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_components/mih_inputs_and_buttons/mih_text_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_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_components/mih_pop_up_messages/mih_loading_circle.dart'; @@ -36,6 +38,7 @@ class _BuildEmployeeListState extends State { TextEditingController fnameController = TextEditingController(); TextEditingController lnameController = TextEditingController(); + final _formKey = GlobalKey(); final baseAPI = AppEnviroment.baseApiUrl; Future updateEmployeeAPICall(int index) async { @@ -140,7 +143,7 @@ class _BuildEmployeeListState extends State { } } - void updateEmployeePopUp(int index) { + void updateEmployeePopUp(int index, double width) { setState(() { accessController.text = widget.employees[index].access; typeController.text = widget.employees[index].title; @@ -176,67 +179,97 @@ class _BuildEmployeeListState extends State { onWindowTapClose: () { Navigator.pop(context); }, - windowBody: Column( - children: [ - const SizedBox(height: 10.0), - MIHTextField( - controller: fnameController, - hintText: "First Name", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: lnameController, - hintText: "Surname", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: typeController, - hintText: "Title", - dropdownOptions: const ["Doctor", "Assistant"], - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: accessController, - hintText: "Access", - dropdownOptions: const ["Full", "Partial"], - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 15.0), - MihButton( - onPressed: () { - if (isRequiredFieldsCaptured()) { - updateEmployeeAPICall(index); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Update", - 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( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: fnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "First Name", + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: lnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Surname", + ), + const SizedBox(height: 15.0), + MIHDropdownField( + controller: typeController, + hintText: "Title", + dropdownOptions: const ["Doctor", "Assistant"], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 10.0), + MIHDropdownField( + controller: accessController, + hintText: "Access", + dropdownOptions: const ["Full", "Partial"], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 20.0), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + if (isRequiredFieldsCaptured()) { + updateEmployeeAPICall(index); + } 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( + "Update", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), - ), - ], + ], + ), ), ), ); @@ -264,6 +297,7 @@ class _BuildEmployeeListState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -291,7 +325,7 @@ class _BuildEmployeeListState extends State { ), ), onTap: () { - updateEmployeePopUp(index); + updateEmployeePopUp(index, screenWidth); }, ); }, 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 14d0998a..c2709027 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 @@ -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_inputs_and_buttons/mih_dropdown_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_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'; @@ -31,9 +33,10 @@ class BuildUserList extends StatefulWidget { class _BuildUserListState extends State { TextEditingController accessController = TextEditingController(); TextEditingController typeController = TextEditingController(); - TextEditingController fnameController = TextEditingController(); - TextEditingController lnameController = TextEditingController(); + TextEditingController usernameController = TextEditingController(); + TextEditingController emailController = TextEditingController(); + final _formKey = GlobalKey(); final baseAPI = AppEnviroment.baseApiUrl; Future createBusinessUserAPICall(int index) async { @@ -112,14 +115,14 @@ class _BuildUserListState extends State { return "$firstLetter********@$end"; } - void addEmployeePopUp(int index) { + void addEmployeePopUp(int index, double width) { setState(() { //accessController.text = widget.users[index].access; //typeController.text = widget.users[index].title; // var fnameInitial = widget.users[index].fname[0]; // var lnameInitial = widget.users[index].lname[0]; - fnameController.text = widget.users[index].username; - lnameController.text = hideEmail(widget.users[index].email); + usernameController.text = widget.users[index].username; + emailController.text = hideEmail(widget.users[index].email); }); showDialog( context: context, @@ -127,70 +130,102 @@ class _BuildUserListState extends State { builder: (context) => MihPackageWindow( fullscreen: false, windowTitle: "Add Employee", - windowBody: Column( - children: [ - const SizedBox(height: 10.0), - MIHTextField( - controller: fnameController, - hintText: "Username Name", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: lnameController, - hintText: "Email", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: typeController, - hintText: "Title", - dropdownOptions: const ["Doctor", "Assistant"], - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: accessController, - hintText: "Access", - dropdownOptions: const ["Full", "Partial"], - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 15.0), - MihButton( - onPressed: () { - if (isRequiredFieldsCaptured()) { - createBusinessUserAPICall(index); - } 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, - ), + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: usernameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Username", + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: emailController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Email", + ), + const SizedBox(height: 15.0), + MIHDropdownField( + controller: typeController, + hintText: "Title", + dropdownOptions: const ["Doctor", "Assistant"], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 10.0), + MIHDropdownField( + controller: accessController, + hintText: "Access", + dropdownOptions: const ["Full", "Partial"], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 15.0), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + if (isRequiredFieldsCaptured()) { + createBusinessUserAPICall(index); + } 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, + ), + ), + ), + ), + ], ), - ), - const SizedBox(height: 10.0), - ], + ], + ), ), onWindowTapClose: () { Navigator.pop(context); @@ -201,13 +236,14 @@ class _BuildUserListState extends State { void dispose() { accessController.dispose(); typeController.dispose(); - fnameController.dispose(); - lnameController.dispose(); + usernameController.dispose(); + emailController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -232,7 +268,7 @@ class _BuildUserListState extends State { ), ), onTap: () { - addEmployeePopUp(index); + addEmployeePopUp(index, screenWidth); }, ); }, 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 3e764e39..0d2773cc 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 @@ -1,15 +1,19 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.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_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_components/mih_inputs_and_buttons/mih_text_input.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_package_tool_body.dart'; 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_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'; @@ -39,17 +43,11 @@ class _MihBusinessDetailsState extends State { final contactController = TextEditingController(); final emailController = TextEditingController(); final locationController = TextEditingController(); + final _formKey = GlobalKey(); late String env; Future submitForm() async { - if (!isEmailValid()) { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Invalid Email"); - }, - ); - } else if (isFormFilled()) { + if (isFormFilled()) { int statusCode = 0; statusCode = await MihBusinessDetailsApi().updateBusinessDetails( widget.arguments.business!.business_id, @@ -180,14 +178,7 @@ class _MihBusinessDetailsState extends State { } bool isFormFilled() { - if (regController.text.isEmpty || - nameController.text.isEmpty || - typeController.text.isEmpty || - practiceNoController.text.isEmpty || - vatNoController.text.isEmpty || - contactController.text.isEmpty || - emailController.text.isEmpty || - locationController.text.isEmpty) { + if (typeController.text.isEmpty) { return false; } else { return true; @@ -233,144 +224,224 @@ class _MihBusinessDetailsState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MihPackageToolBody( borderOn: false, innerHorizontalPadding: 10, - bodyItem: getBody(context), + bodyItem: getBody(screenWidth, context), ); } - Widget getBody(BuildContext context) { + Widget getBody(double width, BuildContext context) { return MihSingleChildScroll( - child: Column( - children: [ - MihCircleAvatar( - imageFile: widget.logoImage, - width: 150, - editable: true, - fileNameController: fileNameController, - userSelectedfile: imageFile, - frameColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - backgroundColor: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - onChange: (selectedfile) { - setState(() { - imageFile = selectedfile; - }); - }, - ), - Visibility( - visible: false, - child: MIHTextField( - controller: fileNameController, - hintText: "Selected File Name", - editable: false, - required: false, - ), - ), - const SizedBox(height: 20), - MIHTextField( - controller: regController, - hintText: "Registration No.", - editable: true, - required: true, - ), - const SizedBox(height: 10), - MIHTextField( - controller: nameController, - hintText: "Business Name", - editable: true, - required: true, - ), - const SizedBox(height: 10), - MIHTextField( - controller: typeController, - hintText: "Business Type", - editable: true, - required: true, - ), - const SizedBox(height: 10), - MIHTextField( - controller: practiceNoController, - hintText: "Practice Number", - editable: true, - required: true, - ), - const SizedBox(height: 10), - MIHTextField( - controller: vatNoController, - hintText: "VAT Number", - editable: true, - required: true, - ), - const SizedBox(height: 10), - MIHTextField( - controller: contactController, - hintText: "Contact Number", - editable: true, - required: true, - ), - const SizedBox(height: 10), - MIHTextField( - controller: emailController, - hintText: "Email", - editable: true, - required: true, - ), - const SizedBox(height: 10), - Row( - children: [ - Flexible( - child: MIHTextField( - controller: locationController, - hintText: "Location", - editable: false, - required: false, - ), - ), - const SizedBox(width: 10.0), - MihButton( - onPressed: () { - MIHLocationAPI().getGPSPosition(context).then((position) { - if (position != null) { + child: Padding( + padding: MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Center( + child: MihCircleAvatar( + imageFile: widget.logoImage, + width: 150, + editable: true, + fileNameController: fileNameController, + userSelectedfile: imageFile, + frameColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + backgroundColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onChange: (selectedfile) { setState(() { - locationController.text = - "${position.latitude}, ${position.longitude}"; + imageFile = selectedfile; }); - } - }); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 100, - child: Text( - "Set", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + }, ), ), - ), - ], - ), - const SizedBox(height: 15), - MihButton( - onPressed: () { - submitForm(); - }, - buttonColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: fileNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected File Name", + ), + ), + const SizedBox(height: 20), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: regController, + multiLineInput: false, + requiredText: true, + hintText: "Registration No.", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: nameController, + multiLineInput: false, + requiredText: true, + hintText: "Business Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 15), + MIHDropdownField( + controller: typeController, + hintText: "Business Type", + dropdownOptions: const ["Doctors Office", "Other"], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: practiceNoController, + multiLineInput: false, + requiredText: typeController.text == "Doctors Office", + hintText: "Practice Number", + validator: (validateValue) { + return MihValidationServices().isEmpty(validateValue); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: vatNoController, + multiLineInput: false, + requiredText: true, + hintText: "VAT Number", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: contactController, + multiLineInput: false, + requiredText: true, + hintText: "Contact Number", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: emailController, + multiLineInput: false, + requiredText: true, + hintText: "Business Email", + validator: (value) { + return MihValidationServices().validateEmail(value); + }, + ), + const SizedBox(height: 10), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Flexible( + child: MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: locationController, + multiLineInput: false, + requiredText: true, + hintText: "GPS Location", + ), + ), + const SizedBox(width: 10.0), + MihButton( + onPressed: () { + MIHLocationAPI().getGPSPosition(context).then((position) { + if (position != null) { + setState(() { + locationController.text = + "${position.latitude}, ${position.longitude}"; + }); + } + }); + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + width: 100, + child: Text( + "Set", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 15), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(height: 20), + ], ), - ), - ], + ], + ), )); } } 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 a847e052..06d64467 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 @@ -1,16 +1,19 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_file_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_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_inputs_and_buttons/mih_text_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_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_image_display.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_success_message.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; @@ -42,15 +45,11 @@ class _MihMyBusinessUserState extends State { final lnameController = TextEditingController(); final accessController = TextEditingController(); final signtureController = TextEditingController(); + final _formKey = GlobalKey(); late String env; bool isFormFilled() { - if (signtureController.text.isEmpty || - titleDropdownController.text.isEmpty || - titleTextController.text.isEmpty || - fnameController.text.isEmpty || - lnameController.text.isEmpty || - accessController.text.isEmpty) { + if (titleDropdownController.text.isEmpty) { return false; } else { return true; @@ -205,127 +204,193 @@ class _MihMyBusinessUserState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MihPackageToolBody( borderOn: false, innerHorizontalPadding: 10, - bodyItem: getBody(), + bodyItem: getBody(screenWidth), ); } - Widget getBody() { + Widget getBody(double width) { return MihSingleChildScroll( - child: Column( - children: [ - MihCircleAvatar( - imageFile: widget.userProPicImage, - width: 150, - editable: false, - fileNameController: fileNameController, - userSelectedfile: userPicFile, - frameColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - backgroundColor: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - onChange: (_) {}, - ), - Visibility( - visible: false, - child: MIHTextField( - controller: fileNameController, - hintText: "Selected File Name", - editable: false, - required: false, + child: Padding( + padding: MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Center( + child: MihCircleAvatar( + imageFile: widget.userProPicImage, + width: 150, + editable: false, + fileNameController: fileNameController, + userSelectedfile: userPicFile, + frameColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + backgroundColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onChange: (_) {}, + ), + ), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: fileNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected File Name", + ), + ), + const SizedBox(height: 20), + MIHDropdownField( + controller: titleDropdownController, + hintText: "Title", + dropdownOptions: const ["Doctor", "Assistant", "Other"], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: titleTextController, + multiLineInput: false, + requiredText: true, + hintText: "Other Title", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: fnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: lnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Surname", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: accessController, + multiLineInput: false, + requiredText: true, + hintText: "Access Level", + readOnly: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + Container( + width: 300, + alignment: Alignment.topLeft, + child: const Text( + "Signature:", + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + Center( + child: MihImageDisplay( + imageFile: widget.userSignatureImage, + width: 300, + height: 200, + editable: true, + fileNameController: signtureController, + userSelectedfile: userSignatureFile, + onChange: (selectedFile) { + setState(() { + userSignatureFile = selectedFile; + }); + }, + ), + ), + const SizedBox(height: 10), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: fileNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected Signature File", + ), + ), + const SizedBox(height: 15), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(height: 20), + ], ), - ), - const SizedBox(height: 20), - MIHDropdownField( - controller: titleDropdownController, - hintText: "Title", - dropdownOptions: const ["Doctor", "Assistant", "Other"], - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10), - MIHTextField( - controller: titleTextController, - hintText: "Other Title", - editable: true, - required: true, - ), - const SizedBox(height: 10), - MIHTextField( - controller: fnameController, - hintText: "Name", - editable: false, - required: true, - ), - const SizedBox(height: 10), - MIHTextField( - controller: lnameController, - hintText: "Surname", - editable: false, - required: true, - ), - const SizedBox(height: 10), - MIHTextField( - controller: accessController, - hintText: "Access Level", - editable: false, - required: true, - ), - const SizedBox(height: 10), - Container( - width: 300, - alignment: Alignment.topLeft, - child: const Text( - "Signature:", - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - ), - MihImageDisplay( - imageFile: widget.userSignatureImage, - width: 300, - height: 200, - editable: true, - fileNameController: signtureController, - userSelectedfile: userSignatureFile, - onChange: (selectedFile) { - setState(() { - userSignatureFile = selectedFile; - }); - }, - ), - const SizedBox(height: 10), - Visibility( - visible: false, - child: MIHTextField( - controller: signtureController, - hintText: "Selected Signature File", - editable: false, - required: true, - ), - ), - const SizedBox(height: 15), - MihButton( - onPressed: () { - submitForm(); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ], + ], + ), ), ); } 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 17b48760..b746bdcb 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 @@ -2,17 +2,20 @@ import 'dart:convert'; import 'package:http/http.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_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_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_inputs_and_buttons/mih_text_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_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'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; @@ -60,6 +63,7 @@ class _ProfileBusinessAddState extends State { PlatformFile? selectedSignature; final ValueNotifier busType = ValueNotifier(""); + final _formKey = GlobalKey(); late String env; // Future uploadSelectedFile( @@ -217,17 +221,9 @@ class _ProfileBusinessAddState extends State { } bool isFieldsFilled() { - if (nameController.text.isEmpty || - typeController.text.isEmpty || - regController.text.isEmpty || - // logonameController.text.isEmpty || - fnameController.text.isEmpty || - lnameController.text.isEmpty || + if (typeController.text.isEmpty || titleController.text.isEmpty || - // signtureController.text.isEmpty || - accessController.text.isEmpty || - contactController.text.isEmpty || - emailController.text.isEmpty) { + accessController.text.isEmpty) { return false; } else { return true; @@ -235,9 +231,7 @@ class _ProfileBusinessAddState extends State { } void submitForm() { - if (!isEmailValid()) { - emailError(); - } else if (isFieldsFilled()) { + if (isFieldsFilled()) { print("Inside submit method"); createBusinessProfileAPICall(); } else { @@ -304,9 +298,9 @@ class _ProfileBusinessAddState extends State { ); } - MIHBody getBody() { + MIHBody getBody(double width) { return MIHBody( - borderOn: true, + borderOn: false, bodyItems: [ KeyboardListener( focusNode: _focusNode, @@ -314,243 +308,298 @@ class _ProfileBusinessAddState extends State { onKeyEvent: (event) async { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.enter) { - submitForm(); + if (_formKey.currentState!.validate()) { + submitForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } } }, child: SingleChildScrollView( - child: Column( - children: [ - //const SizedBox(height: 15), - const Text( - "My Business Details", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 25, - ), - ), - Divider( - color: MzanziInnovationHub.of(context)! - .theme - .secondaryColor()), - const SizedBox(height: 10.0), - // MihCircleAvatar( - // imageFile: logoPreview, - // width: 150, - // editable: true, - // fileNameController: logonameController, - // userSelectedfile: selectedLogo, - // frameColor: - // MzanziInnovationHub.of(context)!.theme.secondaryColor(), - // backgroundColor: - // MzanziInnovationHub.of(context)!.theme.primaryColor(), - // onChange: (selectedfile) { - // setState(() { - // selectedLogo = selectedfile; - // }); - // }, - // ), - // const SizedBox(height: 10.0), - // Visibility( - // visible: true, - // child: MIHTextField( - // controller: logonameController, - // hintText: "Selected Logo File Name", - // editable: false, - // required: true, - // ), - // ), - // const SizedBox(height: 10.0), - MIHTextField( - controller: regController, - hintText: "Registration No.", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: nameController, - hintText: "Business Name", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: typeController, - hintText: "Business Type", - dropdownOptions: const ["Doctors Office", "Other"], - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10.0), - ValueListenableBuilder( - valueListenable: busType, - builder: (BuildContext context, String value, Widget? child) { - return Visibility( - visible: value == "Doctors Office", - child: MIHTextField( - controller: practiceNoController, - hintText: "Practice Number", - editable: true, - required: true, - ), - ); - }, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: vatNoController, - hintText: "VAT Number", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: contactController, - hintText: "Contact Number", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: emailController, - hintText: "Email", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - // MIHFileField( - // controller: logonameController, - // hintText: "Logo", - // editable: false, - // required: true, - // onPressed: () async { - // FilePickerResult? result = - // await FilePicker.platform.pickFiles( - // type: FileType.custom, - // allowedExtensions: ['jpg', 'png', 'pdf'], - // ); - // if (result == null) return; - // final selectedFile = result.files.first; - // setState(() { - // selectedLogo = selectedFile; - // }); - // setState(() { - // logonameController.text = selectedFile.name; - // }); - // }, - // ), - const SizedBox(height: 10.0), - Row( - children: [ - Flexible( - child: MIHTextField( - controller: locationController, - hintText: "Location", - editable: false, - required: false, - ), + child: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + children: [ + const Text( + "My Business Details", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 25, ), - const SizedBox(width: 10.0), - MihButton( - onPressed: () { - MIHLocationAPI() - .getGPSPosition(context) - .then((position) { - if (position != null) { - setState(() { - locationController.text = - "${position.latitude}, ${position.longitude}"; - }); - } - }); - }, - buttonColor: MzanziInnovationHub.of(context)! + ), + Divider( + color: MzanziInnovationHub.of(context)! .theme - .secondaryColor(), - width: 100, - child: Text( - "Set", - style: TextStyle( - color: MzanziInnovationHub.of(context)! - .theme - .primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + .secondaryColor()), + const SizedBox(height: 10.0), + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: regController, + multiLineInput: false, + requiredText: true, + hintText: "Registration No.", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: nameController, + multiLineInput: false, + requiredText: true, + hintText: "Business Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 15.0), + MIHDropdownField( + controller: typeController, + hintText: "Business Type", + dropdownOptions: const ["Doctors Office", "Other"], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 10.0), + ValueListenableBuilder( + valueListenable: busType, + builder: (BuildContext context, String value, + Widget? child) { + return Visibility( + visible: value == "Doctors Office", + child: MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: practiceNoController, + multiLineInput: false, + requiredText: true, + hintText: "Practice Number", + validator: (validateValue) { + if (value == "Doctors Office") { + return MihValidationServices() + .isEmpty(validateValue); + } + return null; + }, + ), + ); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: vatNoController, + multiLineInput: false, + requiredText: true, + hintText: "VAT Number", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: contactController, + multiLineInput: false, + requiredText: true, + hintText: "Contact Number", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: emailController, + multiLineInput: false, + requiredText: true, + hintText: "Business Email", + validator: (value) { + return MihValidationServices().validateEmail(value); + }, + ), + const SizedBox(height: 10.0), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Flexible( + child: MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: locationController, + multiLineInput: false, + requiredText: true, + hintText: "GPS Location", + ), + ), + const SizedBox(width: 10.0), + MihButton( + onPressed: () { + MIHLocationAPI() + .getGPSPosition(context) + .then((position) { + if (position != null) { + setState(() { + locationController.text = + "${position.latitude}, ${position.longitude}"; + }); + } + }); + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 100, + child: Text( + "Set", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 15.0), + //const SizedBox(height: 15.0), + const Center( + child: Text( + "My Business User", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 22, + ), ), ), - ), - ], - ), - - const SizedBox(height: 15.0), - Divider( - color: - MzanziInnovationHub.of(context)?.theme.secondaryColor(), - ), - //const SizedBox(height: 15.0), - const Text( - "My Business User", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 22, + Divider( + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor()), + const SizedBox(height: 10.0), + MIHDropdownField( + controller: titleController, + hintText: "Title", + dropdownOptions: const ["Doctor", "Assistant"], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: fnameController, + multiLineInput: false, + requiredText: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: lnameController, + multiLineInput: false, + requiredText: true, + hintText: "Surname", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 15.0), + MIHDropdownField( + controller: accessController, + hintText: "Access", + dropdownOptions: const ["Full", "Partial"], + required: true, + editable: false, + enableSearch: false, + ), + const SizedBox(height: 20.0), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(); + } 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, + ), + ), + ), + ), + ], ), - ), - Divider( - color: MzanziInnovationHub.of(context)! - .theme - .secondaryColor()), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: titleController, - hintText: "Title", - dropdownOptions: const ["Doctor", "Assistant"], - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: fnameController, - hintText: "Name", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: lnameController, - hintText: "Surname", - editable: false, - required: true, - ), - const SizedBox(height: 15.0), - MIHDropdownField( - controller: accessController, - hintText: "Access", - dropdownOptions: const ["Full", "Partial"], - required: true, - editable: false, - enableSearch: false, - ), - const SizedBox(height: 30.0), - MihButton( - onPressed: () { - submitForm(); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Add", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ], + ], + ), ), ), ), @@ -596,11 +645,12 @@ class _ProfileBusinessAddState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MIHLayoutBuilder( actionButton: getActionButton(), secondaryActionButton: null, header: getHeader(), - body: getBody(), + body: getBody(screenWidth), actionDrawer: null, secondaryActionDrawer: null, bottomNavBar: null, 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 f6811854..973b1f92 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 @@ -1,15 +1,17 @@ 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_file_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_user_apis.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_file_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_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_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'; 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_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'; @@ -39,6 +41,7 @@ class _MihPersonalProfileState extends State { late bool businessUser; late String oldProPicName; late String env; + final _formKey = GlobalKey(); void notUniqueAlert() { showDialog( @@ -65,38 +68,19 @@ class _MihPersonalProfileState extends State { Future submitForm() async { // print("============\nsubmiit form\n================="); - if (isFieldsFilled()) { - if (widget.arguments.signedInUser.username != usernameController.text) { - bool isUsernameUnique = await MihUserApis.isUsernameUnique( - usernameController.text, context); - print("isUsernameUnique: $isUsernameUnique"); - if (isUsernameUnique == false) { - notUniqueAlert(); - return; - } + if (widget.arguments.signedInUser.username != usernameController.text) { + bool isUsernameUnique = + await MihUserApis.isUsernameUnique(usernameController.text, context); + print("isUsernameUnique: $isUsernameUnique"); + if (isUsernameUnique == false) { + notUniqueAlert(); + return; } - if (oldProPicName != proPicController.text) { - await uploadSelectedFile(proPic); - } - await updateUserApiCall(); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); } - } - - bool isFieldsFilled() { - if (fnameController.text.isEmpty || - lnameController.text.isEmpty || - usernameController.text.isEmpty) { - return false; - } else { - return true; + if (oldProPicName != proPicController.text) { + await uploadSelectedFile(proPic); } + await updateUserApiCall(); } bool isBusinessUser() { @@ -252,146 +236,156 @@ class _MihPersonalProfileState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MihPackageToolBody( borderOn: false, innerHorizontalPadding: 10, - bodyItem: getBody(), + bodyItem: getBody(screenWidth), ); } - Widget getBody() { + Widget getBody(double width) { return MihSingleChildScroll( - child: Column( - children: [ - //displayProPic(), - MihCircleAvatar( - imageFile: propicPreview, - width: 150, - editable: true, - fileNameController: proPicController, - userSelectedfile: proPic, - frameColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - backgroundColor: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - onChange: (selectedImage) { - setState(() { - proPic = selectedImage; - }); - }, - ), - // MIHProfilePicture( - // profilePictureFile: widget.arguments.propicFile, - // proPicController: proPicController, - // proPic: proPic, - // width: 155, - // radius: 70, - // drawerMode: false, - // editable: true, - // frameColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - // onChange: (newProPic) { - // setState(() { - // proPic = newProPic; - // }); - // }, - // ), - const SizedBox(height: 25.0), - Visibility( - visible: false, - child: MIHFileField( - controller: proPicController, - hintText: "Profile Picture", - editable: false, - required: false, - onPressed: () async { - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: ['jpg', 'png'], - withData: true, - ); - if (result == null) return; - final selectedFile = result.files.first; - setState(() { - proPic = selectedFile; - propicPreview = MemoryImage(proPic!.bytes!); - }); - - setState(() { - proPicController.text = selectedFile.name; - }); - }, - ), - ), - // const SizedBox(height: 10.0), - // MIHTextField( - // controller: proPicController, - // hintText: "Pro Pic", - // editable: true, - // required: true, - // ), - const SizedBox(height: 10.0), - MIHTextField( - controller: usernameController, - hintText: "Username", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: fnameController, - hintText: "First Name", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: lnameController, - hintText: "Last Name", - editable: true, - required: true, - ), - 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, + child: Padding( + padding: MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Center( + child: MihCircleAvatar( + imageFile: propicPreview, + width: 150, + editable: true, + fileNameController: proPicController, + userSelectedfile: proPic, + frameColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + backgroundColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onChange: (selectedImage) { + setState(() { + proPic = selectedImage; + }); + }, + ), ), - ), - const SizedBox( - width: 10, - ), - Switch( - value: businessUser, - onChanged: (bool value) { - setState(() { - businessUser = value; - }); - }, - ), - ], - ), - const SizedBox(height: 30.0), - MihButton( - onPressed: () { - submitForm(); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + const SizedBox(height: 25.0), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: proPicController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected File Name", + ), + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: usernameController, + multiLineInput: false, + requiredText: true, + hintText: "Username", + validator: (value) { + return MihValidationServices().validateUsername(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: fnameController, + multiLineInput: false, + requiredText: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: lnameController, + multiLineInput: false, + requiredText: true, + hintText: "Last Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + 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; + }); + }, + ), + ], + ), + const SizedBox(height: 30.0), + Center( + child: MihButton( + onPressed: () { + //Add validation here + if (_formKey.currentState!.validate()) { + submitForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), - ), - ], + ], + ), ), ); } diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart index f9a7739a..4da80cf9 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart @@ -118,40 +118,30 @@ class _MihPersonalSettingsState extends State { ), ), const SizedBox(height: 10.0), - Wrap( - spacing: 10, - runSpacing: 10, - alignment: WrapAlignment.center, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - Text( - "Would you like to delete your MIH account?", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), + Text( + "Would you like to delete your MIH account?", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + ), + ), + const SizedBox(height: 10.0), + MihButton( + onPressed: () { + deleteAccountPopUp(context); + }, + buttonColor: MzanziInnovationHub.of(context)!.theme.errorColor(), + width: 300, + child: Text( + "Delete Account", + style: TextStyle( + color: MzanziInnovationHub.of(context)!.theme.primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, ), - MihButton( - onPressed: () { - deleteAccountPopUp(context); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.errorColor(), - width: 300, - child: Text( - "Delete Account", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ], + ), ), ], ), diff --git a/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart b/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart index 8b3366df..a5296b72 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart @@ -1,19 +1,18 @@ 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_mzansi_wallet_apis.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_number_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_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_form.dart'; 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_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_delete_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_card_display.dart'; import 'package:flutter/material.dart'; - -// import 'package:syncfusion_flutter_barcodes/barcodes.dart'; import 'package:barcode_widget/barcode_widget.dart'; class BuildLoyaltyCardList extends StatefulWidget { @@ -36,6 +35,7 @@ class _BuildLoyaltyCardListState extends State { final TextEditingController _nicknameController = TextEditingController(); final TextEditingController _cardNumberController = TextEditingController(); late int _noFavourites; + final _formKey = GlobalKey(); void openscanner() async { Navigator.of(context).pushNamed( @@ -44,7 +44,7 @@ class _BuildLoyaltyCardListState extends State { ); } - void editCardWindow(BuildContext ctxt, int index) { + void editCardWindow(BuildContext ctxt, int index, double width) { showDialog( context: context, barrierDismissible: false, @@ -56,86 +56,111 @@ class _BuildLoyaltyCardListState extends State { _nicknameController.clear(); Navigator.pop(context); }, - windowBody: Column( - children: [ - const SizedBox(height: 10), - MIHTextField( - controller: _nicknameController, - hintText: "Card Title", - editable: true, - required: false, - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - Flexible( - child: MIHNumberField( - controller: _cardNumberController, - hintText: "Card Number", - editable: true, - required: true, - enableDecimal: false, + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : EdgeInsets.symmetric(horizontal: width * 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _nicknameController, + multiLineInput: false, + requiredText: false, + hintText: "Card Title", ), - ), - const SizedBox(width: 10), - MihButton( - onPressed: () { - openscanner(); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 100, - child: Text( - "Scan", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: _cardNumberController, + multiLineInput: false, + requiredText: true, + hintText: "Card Number", + numberMode: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + ), + const SizedBox(width: 20), + MihButton( + onPressed: () { + openscanner(); + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 100, + child: Text( + "Scan", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 15), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + MIHMzansiWalletApis.updateLoyaltyCardAPICall( + widget.signedInUser, + widget.cardList[index].idloyalty_cards, + widget.cardList[index].favourite, + widget.cardList[index].priority_index, + _nicknameController.text, + _cardNumberController.text, + 0, + ctxt, + ); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), ), ), - ), - ], - ), - const SizedBox(height: 15), - MihButton( - onPressed: () { - if (_cardNumberController.text == "") { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } else { - MIHMzansiWalletApis.updateLoyaltyCardAPICall( - widget.signedInUser, - widget.cardList[index].idloyalty_cards, - widget.cardList[index].favourite, - widget.cardList[index].priority_index, - _nicknameController.text, - _cardNumberController.text, - 0, - ctxt, - ); - } - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + ], ), - ), - ], + ], + ), ), ), ); @@ -278,7 +303,7 @@ class _BuildLoyaltyCardListState extends State { ); } - void viewCardWindow(int index) { + void viewCardWindow(int index, double width) { //print(widget.cardList[index].card_number); String formattedCardNumber = ""; for (int i = 0; i <= widget.cardList[index].card_number.length - 1; i++) { @@ -344,7 +369,7 @@ class _BuildLoyaltyCardListState extends State { _cardNumberController.text = widget.cardList[index].card_number; _nicknameController.text = widget.cardList[index].nickname; }); - editCardWindow(context, index); + editCardWindow(context, index, width); }, ), SpeedDialChild( @@ -488,7 +513,7 @@ class _BuildLoyaltyCardListState extends State { height: 100, ), onTap: () { - viewCardWindow(index); + viewCardWindow(index, size.width); }, ); }, diff --git a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_barcode_scanner.dart b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_barcode_scanner.dart index 9fd7fd2d..52a3e683 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_barcode_scanner.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_barcode_scanner.dart @@ -129,6 +129,7 @@ class _MihBarcodeScannerState extends State .theme .secondaryColor(), width: 100, + height: 50, child: Text( "Cancel", style: TextStyle( 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 3474ecd2..9459f3be 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 @@ -1,15 +1,17 @@ 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_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_inputs_and_buttons/mih_number_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_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'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; @@ -36,6 +38,7 @@ class _MihCardsState extends State { final TextEditingController cardNumberController = TextEditingController(); final TextEditingController cardSearchController = TextEditingController(); final FocusNode searchFocusNode = FocusNode(); + final _formKey = GlobalKey(); late Future> cardList; List listOfCards = []; //bool showSelectedCardType = false; @@ -81,7 +84,7 @@ class _MihCardsState extends State { } } - void addCardWindow(BuildContext ctxt) { + void addCardWindow(BuildContext ctxt, double width) { showDialog( context: context, barrierDismissible: false, @@ -95,154 +98,194 @@ class _MihCardsState extends State { shopName.value = ""; Navigator.pop(context); }, - windowBody: Column( - children: [ - MIHDropdownField( - controller: shopController, - hintText: "Shop Name", - dropdownOptions: const [ - "+More", - "Apple Tree", - "Auchan", - "Best Before", - "Big Save", - "Boxer", - "BP", - "Builders Warehouse", - "Checkers", - "Choppies", - "Clicks", - "Continente", - "Cotton:On", - "Carrefour", - "Dis-Chem", - "Edgars", - "Eskom", - "Exclusive Books", - "Fresh Stop", - "Fresmart", - "Infinity", - "Jet", - "Justrite", - "Kero", - "Leroy Merlin", - "Makro", - "Naivas", - "OK Foods", - "Panarottis", - "Pick n Pay", - "PnA", - "PQ Clothing", - "Rage", - "Sefalana", - "Sasol", - "Shell", - "Shoprite", - "Signature Cosmetics & Fragrances", - "Spar", - "Spur", - "TFG Group", - "Toys R Us", - "Woermann Brock", - "Woolworths" - ], - required: true, - editable: true, - enableSearch: false, - ), - ValueListenableBuilder( - valueListenable: shopName, - builder: (BuildContext context, String value, Widget? child) { - return Visibility( - visible: value != "", - child: Column( + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : EdgeInsets.symmetric(horizontal: width * 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MIHDropdownField( + controller: shopController, + hintText: "Shop Name", + dropdownOptions: const [ + "+More", + "Apple Tree", + "Auchan", + "Best Before", + "Big Save", + "Boxer", + "BP", + "Builders Warehouse", + "Checkers", + "Choppies", + "Clicks", + "Continente", + "Cotton:On", + "Carrefour", + "Dis-Chem", + "Edgars", + "Eskom", + "Exclusive Books", + "Fresh Stop", + "Fresmart", + "Infinity", + "Jet", + "Justrite", + "Kero", + "Leroy Merlin", + "Makro", + "Naivas", + "OK Foods", + "Panarottis", + "Pick n Pay", + "PnA", + "PQ Clothing", + "Rage", + "Sefalana", + "Sasol", + "Shell", + "Shoprite", + "Signature Cosmetics & Fragrances", + "Spar", + "Spur", + "TFG Group", + "Toys R Us", + "Woermann Brock", + "Woolworths" + ], + required: true, + editable: true, + enableSearch: false, + ), + ValueListenableBuilder( + valueListenable: shopName, + builder: + (BuildContext context, String value, Widget? child) { + return Visibility( + visible: value != "", + child: Column( + children: [ + const SizedBox(height: 10), + MihCardDisplay( + shopName: shopName.value, + nickname: "", + height: 200), + ], + ), + ); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _nicknameController, + multiLineInput: false, + requiredText: false, + hintText: "Card Title", + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.max, children: [ - const SizedBox(height: 10), - MihCardDisplay( - shopName: shopName.value, nickname: "", height: 200), + Flexible( + child: MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: cardNumberController, + multiLineInput: false, + requiredText: true, + hintText: "Card Number", + numberMode: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + ), + const SizedBox(width: 20), + MihButton( + onPressed: () { + openscanner(); + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 100, + child: Text( + "Scan", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), ], ), - ); - }, - ), - const SizedBox(height: 10), - MIHTextField( - controller: _nicknameController, - hintText: "Card Title", - editable: true, - required: false, - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - Flexible( - child: MIHNumberField( - controller: cardNumberController, - hintText: "Card Number", - editable: true, - required: true, - enableDecimal: false, - ), - ), - const SizedBox(width: 10), - MihButton( - onPressed: () {}, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 100, - child: Text( - "Scan", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, + const SizedBox(height: 15), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + if (shopController.text == "") { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage( + errorType: "Input Error"); + }, + ); + } else { + MIHMzansiWalletApis.addLoyaltyCardAPICall( + widget.signedInUser, + widget.signedInUser.app_id, + shopController.text, + cardNumberController.text, + "", + 0, + _nicknameController.text, + 0, + context, + ); + } + } 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, + ), + ), ), ), - ), - ], - ), - const SizedBox(height: 15), - MihButton( - onPressed: () { - if (shopController.text == "" || - cardNumberController.text == "") { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } else { - MIHMzansiWalletApis.addLoyaltyCardAPICall( - widget.signedInUser, - widget.signedInUser.app_id, - shopController.text, - cardNumberController.text, - "", - 0, - _nicknameController.text, - 0, - 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, - ), + ], ), - ), - ], + ], + ), ), ), ); @@ -359,7 +402,7 @@ class _MihCardsState extends State { backgroundColor: MzanziInnovationHub.of(context)!.theme.successColor(), onTap: () { - addCardWindow(context); + addCardWindow(context, width); }, ) ]), 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 868ffefe..ad385451 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 @@ -2,11 +2,10 @@ import 'dart:convert'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_api_calls.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_text_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_time_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_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_success_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_warning_message.dart'; @@ -132,116 +131,6 @@ class _BuildPatientsListState extends State { ); } - void submitApointment(int index) { - //To-Do: Implement the appointment submission - print("To-do: Implement the appointment submission"); - // MIHApiCalls.addAppointmentAPICall( - // widget.business!.business_id, - // widget.patients[index].app_id, - // dateController.text, - // timeController.text, - // widget.arguments, - // context, - // ); - } - - bool isAppointmentFieldsFilled() { - if (dateController.text.isEmpty || timeController.text.isEmpty) { - return false; - } else { - return true; - } - } - - void appointmentPopUp(int index) { - var firstLetterFName = widget.patients[index].first_name[0]; - var firstLetterLName = widget.patients[index].last_name[0]; - var fnameStar = '*' * 8; - var lnameStar = '*' * 8; - - setState(() { - idController.text = widget.patients[index].id_no; - fnameController.text = firstLetterFName + fnameStar; - lnameController.text = firstLetterLName + lnameStar; - }); - showDialog( - context: context, - barrierDismissible: false, - builder: (context) => MihPackageWindow( - fullscreen: false, - windowTitle: "Patient Appointment", - onWindowTapClose: () { - Navigator.pop(context); - }, - windowBody: Column( - children: [ - MIHTextField( - controller: idController, - hintText: "ID No.", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: fnameController, - hintText: "First Name", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: lnameController, - hintText: "Surname", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHDateField( - controller: dateController, - lableText: "Date", - required: true, - ), - const SizedBox(height: 10.0), - MIHTimeField( - controller: timeController, - lableText: "Time", - required: true, - ), - const SizedBox(height: 30.0), - MihButton( - onPressed: () { - bool filled = isAppointmentFieldsFilled(); - if (filled) { - //print("here2"); - submitApointment(index); - //print("here3"); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Book", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ), - ); - } - void noAccessWarning() { showDialog( context: context, @@ -331,32 +220,60 @@ class _BuildPatientsListState extends State { }, windowBody: Column( children: [ - MIHTextField( + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: idController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "ID No.", - editable: false, - required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 10.0), - MIHTextField( + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: fnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "First Name", - editable: false, - required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 10.0), - MIHTextField( + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: lnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "Surname", - editable: false, - required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 10.0), - MIHTextField( + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: accessStatusController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "Access Status", - editable: false, - required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), const SizedBox(height: 20.0), Visibility( 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 c79378fd..273e31f0 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 @@ -1,11 +1,14 @@ 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_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_text_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_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_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'; @@ -41,6 +44,7 @@ class _BuildPatientsListState extends State { TextEditingController idController = TextEditingController(); TextEditingController fnameController = TextEditingController(); TextEditingController lnameController = TextEditingController(); + final _formKey = GlobalKey(); final baseAPI = AppEnviroment.baseApiUrl; @@ -66,18 +70,6 @@ class _BuildPatientsListState extends State { timeController.text, context, ); - // MIHApiCalls.addAppointmentAPICall( - // widget.business!.business_id, - // widget.patientAccesses[index].app_id, - // dateController.text, - // timeController.text, - // BusinessArguments( - // widget.signedInUser, - // widget.businessUser, - // widget.business, - // ), - // context, - // ); } bool isAppointmentFieldsFilled() { @@ -88,10 +80,9 @@ class _BuildPatientsListState extends State { } } - void appointmentPopUp(int index) { + void appointmentPopUp(int index, double width) { var firstLetterFName = widget.patientAccesses[index].fname; var firstLetterLName = widget.patientAccesses[index].lname; - setState(() { idController.text = widget.patientAccesses[index].id_no; fnameController.text = firstLetterFName; @@ -106,68 +97,113 @@ class _BuildPatientsListState extends State { onWindowTapClose: () { Navigator.pop(context); }, - windowBody: Column( - children: [ - MIHTextField( - controller: idController, - hintText: "ID No.", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: fnameController, - hintText: "First Name", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: lnameController, - hintText: "Surname", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHDateField( - controller: dateController, - lableText: "Date", - required: true, - ), - const SizedBox(height: 10.0), - MIHTimeField( - controller: timeController, - lableText: "Time", - required: true, - ), - const SizedBox(height: 30.0), - MihButton( - onPressed: () { - bool filled = isAppointmentFieldsFilled(); - if (filled) { - submitApointment(index); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.056) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: idController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "ID No.", + validator: (value) { + return MihValidationServices().isEmpty(value); }, - ); - } - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Book Appointment", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: fnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: lnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Surname", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MIHDateField( + controller: dateController, + lableText: "Date", + required: true, + ), + const SizedBox(height: 10.0), + MIHTimeField( + controller: timeController, + lableText: "Time", + required: true, + ), + const SizedBox(height: 30.0), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + bool filled = isAppointmentFieldsFilled(); + if (filled) { + submitApointment(index); + } 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( + "Book Appointment", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), - ), - ], + ], + ), ), ), ); @@ -202,10 +238,10 @@ class _BuildPatientsListState extends State { return hasAccess; } - void patientProfileChoicePopUp(int index, Patient? patientProfile) async { + void patientProfileChoicePopUp( + int index, Patient? patientProfile, double width) async { var firstLetterFName = widget.patientAccesses[index].fname; var firstLetterLName = widget.patientAccesses[index].lname; - setState(() { idController.text = widget.patientAccesses[index].id_no; fnameController.text = firstLetterFName; @@ -220,79 +256,119 @@ class _BuildPatientsListState extends State { onWindowTapClose: () { Navigator.pop(context); }, - windowBody: Column( - children: [ - MIHTextField( - controller: idController, - hintText: "ID No.", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: fnameController, - hintText: "First Name", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: lnameController, - hintText: "Surname", - editable: false, - required: true, - ), - const SizedBox(height: 30.0), - Wrap(runSpacing: 10, spacing: 10, children: [ - MihButton( - onPressed: () { - appointmentPopUp(index); - }, - buttonColor: + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Book Appointment", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - MihButton( - onPressed: () { - Navigator.of(context).pushNamed('/patient-manager/patient', - arguments: PatientViewArguments( - widget.signedInUser, - patientProfile, - widget.businessUser, - widget.business, - "business", - )); + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: idController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "ID No.", + validator: (value) { + return MihValidationServices().isEmpty(value); }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.successColor(), - width: 300, - child: Text( - "View Medical Records", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), ), - ]) - ], + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: fnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: lnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Surname", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 30.0), + Center( + child: Wrap( + runSpacing: 10, + spacing: 10, + children: [ + MihButton( + onPressed: () { + appointmentPopUp(index, width); + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 300, + child: Text( + "Book Appointment", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + MihButton( + onPressed: () { + Navigator.of(context) + .pushNamed('/patient-manager/patient', + arguments: PatientViewArguments( + widget.signedInUser, + patientProfile, + widget.businessUser, + widget.business, + "business", + )); + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.successColor(), + width: 300, + child: Text( + "View Medical Records", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ) + ], + ), ), ), ); } - Widget displayMyPatientTile(int index) { + Widget displayMyPatientTile(int index, double width) { var firstName = ""; var lastName = ""; String access = widget.patientAccesses[index].status.toUpperCase(); @@ -350,7 +426,7 @@ class _BuildPatientsListState extends State { p = result; }); }); - patientProfileChoicePopUp(index, p); + patientProfileChoicePopUp(index, p, width); } else { noAccessWarning(index); } @@ -374,6 +450,7 @@ class _BuildPatientsListState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -384,7 +461,7 @@ class _BuildPatientsListState extends State { }, itemCount: widget.patientAccesses.length, itemBuilder: (context, index) { - return displayMyPatientTile(index); + return displayMyPatientTile(index, screenWidth); }, ); } 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 6d378e83..bc5a283e 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 @@ -1,16 +1,18 @@ 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_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_multiline_text_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_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_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_env/env.dart'; @@ -59,9 +61,10 @@ class _WaitingRoomState extends State { late Future> businessAppointmentResults; late Future> appointmentResults; bool inWaitingRoom = true; + final _formKey = GlobalKey(); // Business Appointment Tool - Widget getBusinessAppointmentsTool() { + Widget getBusinessAppointmentsTool(double width) { return Stack( children: [ MihSingleChildScroll( @@ -137,7 +140,7 @@ class _WaitingRoomState extends State { MzanziInnovationHub.of(context)!.theme.successColor(), onTap: () { // addAppointmentWindow(); - appointmentTypeSelection(); + appointmentTypeSelection(width); }, ) ], @@ -203,7 +206,7 @@ class _WaitingRoomState extends State { ); } - void appointmentTypeSelection() { + void appointmentTypeSelection(double width) { String question = "What type of appointment would you like to add?"; question += "\n\nExisting Patient: Add an appointment for an patient your practice has access to."; @@ -274,7 +277,7 @@ class _WaitingRoomState extends State { MihButton( onPressed: () { Navigator.pop(context); - addAppointmentWindow(); + addAppointmentWindow(width); }, buttonColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), @@ -296,7 +299,7 @@ class _WaitingRoomState extends State { ); } - void addAppointmentWindow() { + void addAppointmentWindow(double width) { showDialog( context: context, barrierDismissible: false, @@ -312,65 +315,94 @@ class _WaitingRoomState extends State { _appointmentDescriptionIDController.clear(); _patientController.clear(); }, - windowBody: Column( - children: [ - SizedBox( - // width: 500, - child: MIHTextField( - controller: _appointmentTitleController, - hintText: "Title", - editable: true, - required: true, + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _appointmentTitleController, + multiLineInput: false, + requiredText: true, + hintText: "Appointment Title", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + SizedBox( + // width: 500, + child: MIHDateField( + controller: _appointmentDateController, + lableText: "Date", + required: true, + ), + ), + const SizedBox(height: 10), + SizedBox( + // width: 500, + child: MIHTimeField( + controller: _appointmentTimeController, + lableText: "Time", + required: true, + ), + ), + const SizedBox(height: 10), + MihTextFormField( + height: 250, + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _appointmentDescriptionIDController, + multiLineInput: true, + requiredText: true, + hintText: "Description", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 20), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + addAppointmentCall(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .successColor(), + width: 300, + child: Text( + "Add", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHDateField( - controller: _appointmentDateController, - lableText: "Date", - required: true, - ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - child: MIHTimeField( - controller: _appointmentTimeController, - lableText: "Time", - required: true, - ), - ), - const SizedBox(height: 10), - SizedBox( - // width: 500, - height: 250, - child: MIHMLTextField( - controller: _appointmentDescriptionIDController, - hintText: "Description", - editable: true, - required: true, - ), - ), - const SizedBox(height: 20), - MihButton( - onPressed: () { - addAppointmentCall(); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.successColor(), - width: 300, - child: Text( - "Add", - style: TextStyle( - color: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ], + ], + ), ), ); }, @@ -413,8 +445,7 @@ class _WaitingRoomState extends State { } bool isAppointmentInputValid() { - if (_appointmentTitleController.text.isEmpty || - _appointmentDescriptionIDController.text.isEmpty || + if (_appointmentDescriptionIDController.text.isEmpty || _appointmentDateController.text.isEmpty || _appointmentTimeController.text.isEmpty) { return false; @@ -458,9 +489,10 @@ class _WaitingRoomState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MihPackageToolBody( borderOn: false, - bodyItem: getBusinessAppointmentsTool(), + bodyItem: getBusinessAppointmentsTool(screenWidth), ); } } diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/Claim_Statement_Window.dart index 6efd0697..61e185c9 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,13 +1,17 @@ +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_inputs_and_buttons/mih_text_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_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'; import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; @@ -66,6 +70,7 @@ class _ClaimStatementWindowState extends State { final ValueNotifier medAid = ValueNotifier(""); List icd10codeList = []; final FocusNode _searchFocusNode = FocusNode(); + final _formKey = GlobalKey(); void icd10SearchWindow(List codeList) { showDialog( @@ -78,220 +83,303 @@ class _ClaimStatementWindowState extends State { ); } - Widget getWindowBody() { - return Column( - children: [ - MIHDropdownField( - controller: _docTypeController, - hintText: "Document Type", - dropdownOptions: const ["Claim", "Statement"], - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10), - Text( - "Service Details", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - const SizedBox(height: 10), - MIHDateField( - controller: _serviceDateController, - lableText: "Date of Service", - required: true, - ), - const SizedBox(height: 10), - MIHDropdownField( - controller: _serviceDescController, - hintText: "Service Decription", - dropdownOptions: const [ - "Consultation", - "Procedure", - "Other", - ], - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10), - ValueListenableBuilder( - valueListenable: serviceDesc, - builder: (BuildContext context, String value, Widget? child) { - Widget returnWidget; - switch (value) { - case 'Consultation': - returnWidget = Column( - children: [ - MIHDropdownField( - controller: _serviceDescOptionsController, - hintText: "Service Decription Options", - dropdownOptions: const [ - "General Consultation", - "Follow-Up Consultation", - "Specialist Consultation", - "Emergency Consultation", - ], - required: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10), - ], - ); - case 'Procedure': - returnWidget = Column( - children: [ - MIHTextField( - controller: _prcedureNameController, - hintText: "Procedure Name", - editable: true, - required: true, - ), - const SizedBox(height: 10), - // MIHDateField( - // controller: _procedureDateController, - // lableText: "Procedure Date", - // required: true, - // ), - // const SizedBox(height: 10), - MIHTextField( - controller: _proceedureAdditionalInfoController, - hintText: "Additional Information", - editable: true, - required: true, - ), - const SizedBox(height: 10), - ], - ); - case 'Other': - returnWidget = Column( - children: [ - MIHTextField( - controller: _serviceDescOptionsController, - hintText: "Service Decription text", - editable: false, - required: true, - ), - const SizedBox(height: 10), - ], - ); - default: - returnWidget = const SizedBox(); - } - return returnWidget; - }, - ), - //const SizedBox(height: 10), - MihSearchBar( - controller: _icd10CodeController, - hintText: "ICD-10 Code & Description", - prefixIcon: Icons.search, - fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - onPrefixIconTap: () { - MIHIcd10CodeApis.getIcd10Codes(_icd10CodeController.text, context) - .then((result) { - icd10SearchWindow(result); - }); - }, - onClearIconTap: () { - _icd10CodeController.clear(); - }, - searchFocusNode: _searchFocusNode, - ), - const SizedBox(height: 10), - MIHTextField( - controller: _amountController, - hintText: "Amount", - editable: true, - required: true, - ), - Text( - "Additional Infomation", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - const SizedBox(height: 10), - MIHTextField( - controller: _preauthNoController, - hintText: "Pre-authorisation No.", - editable: true, - required: false, - ), - const SizedBox(height: 15), - MihButton( - onPressed: () { - if (isInputValid()) { - MIHClaimStatementGenerationApi().generateClaimStatement( - ClaimStatementGenerationArguments( - _docTypeController.text, - widget.selectedPatient.app_id, - _fullNameController.text, - _idController.text, - _medAidController.text, - _medAidNoController.text, - _medAidCodeController.text, - _medAidNameController.text, - _medAidSchemeController.text, - widget.business!.Name, - "*To-Be Added*", - widget.business!.contact_no, - widget.business!.bus_email, - _providerNameController.text, - _practiceNoController.text, - _vatNoController.text, - _serviceDateController.text, - _serviceDescController.text, - _serviceDescOptionsController.text, - _prcedureNameController.text, - _proceedureAdditionalInfoController.text, - _icd10CodeController.text, - _amountController.text, - _preauthNoController.text, - widget.business!.logo_path, - widget.businessUser!.sig_path, + Widget getWindowBody(double width) { + return Padding( + padding: MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MIHDropdownField( + controller: _docTypeController, + hintText: "Document Type", + dropdownOptions: const ["Claim", "Statement"], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 10), + Center( + child: Text( + "Service Details", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), ), - PatientViewArguments( - widget.signedInUser, - widget.selectedPatient, - widget.businessUser, - widget.business, - "business", - ), - widget.env, - context); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); + ), + ), + Divider( + color: + MzanziInnovationHub.of(context)!.theme.secondaryColor()), + const SizedBox(height: 10), + MIHDateField( + controller: _serviceDateController, + lableText: "Date of Service", + required: true, + ), + const SizedBox(height: 10), + MIHDropdownField( + controller: _serviceDescController, + hintText: "Service Decription", + dropdownOptions: const [ + "Consultation", + "Procedure", + "Other", + ], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 10), + ValueListenableBuilder( + valueListenable: serviceDesc, + builder: (BuildContext context, String value, Widget? child) { + Widget returnWidget; + switch (value) { + case 'Consultation': + returnWidget = Column( + 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, + ), + ), + const SizedBox(height: 10), + ], + ); + case 'Procedure': + returnWidget = Column( + children: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: _prcedureNameController, + multiLineInput: false, + requiredText: true, + hintText: "Procedure Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: _proceedureAdditionalInfoController, + multiLineInput: false, + requiredText: true, + hintText: "Additional Information", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 15), + ], + ); + case 'Other': + returnWidget = Column( + children: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: _serviceDescOptionsController, + multiLineInput: false, + requiredText: true, + hintText: "Service Description Details", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + ], + ); + default: + returnWidget = const SizedBox(); + } + return returnWidget; }, - ); - } - }, - buttonColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Generate", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + ), + Column( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text("ICD-10 Code & Description", + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + )), + ), + const SizedBox(height: 4), + MihSearchBar( + controller: _icd10CodeController, + hintText: "ICD-10 Search", + prefixIcon: Icons.search, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + MIHIcd10CodeApis.getIcd10Codes( + _icd10CodeController.text, context) + .then((result) { + icd10SearchWindow(result); + }); + }, + onClearIconTap: () { + _icd10CodeController.clear(); + }, + searchFocusNode: _searchFocusNode, + ), + ], + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _amountController, + multiLineInput: false, + requiredText: true, + numberMode: true, + hintText: "Service Cost", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + Center( + child: Text( + "Additional Infomation", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + ), + ), + ), + Divider( + color: + MzanziInnovationHub.of(context)!.theme.secondaryColor()), + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: _preauthNoController, + multiLineInput: false, + requiredText: false, + hintText: "Pre-authorisation No.", + ), + const SizedBox(height: 20), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + if (isInputValid()) { + MIHClaimStatementGenerationApi().generateClaimStatement( + ClaimStatementGenerationArguments( + _docTypeController.text, + widget.selectedPatient.app_id, + _fullNameController.text, + _idController.text, + _medAidController.text, + _medAidNoController.text, + _medAidCodeController.text, + _medAidNameController.text, + _medAidSchemeController.text, + widget.business!.Name, + "*To-Be Added*", + widget.business!.contact_no, + widget.business!.bus_email, + _providerNameController.text, + _practiceNoController.text, + _vatNoController.text, + _serviceDateController.text, + _serviceDescController.text, + _serviceDescOptionsController.text, + _prcedureNameController.text, + _proceedureAdditionalInfoController.text, + _icd10CodeController.text, + _amountController.text, + _preauthNoController.text, + widget.business!.logo_path, + widget.businessUser!.sig_path, + ), + PatientViewArguments( + widget.signedInUser, + widget.selectedPatient, + widget.businessUser, + widget.business, + "business", + ), + widget.env, + context); + } 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( + "Generate", + style: TextStyle( + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), - ), - ], + ], + ), ); } @@ -312,28 +400,14 @@ class _ClaimStatementWindowState extends State { } bool isInputValid() { - switch (_serviceDescController.text) { - case 'Procedure': - if (_docTypeController.text.isEmpty || - _serviceDateController.text.isEmpty || - _icd10CodeController.text.isEmpty || - _amountController.text.isEmpty || - _prcedureNameController.text.isEmpty || - _proceedureAdditionalInfoController.text.isEmpty) { - return false; - } else { - return true; - } - default: - if (_docTypeController.text.isEmpty || - _serviceDateController.text.isEmpty || - _icd10CodeController.text.isEmpty || - _amountController.text.isEmpty || - _serviceDescOptionsController.text.isEmpty) { - return false; - } else { - return true; - } + if (_docTypeController.text.isEmpty || + _serviceDateController.text.isEmpty || + _icd10CodeController.text.isEmpty || + _amountController.text.isEmpty || + _serviceDescOptionsController.text.isEmpty) { + return false; + } else { + return true; } } @@ -397,19 +471,14 @@ class _ClaimStatementWindowState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MihPackageWindow( fullscreen: false, windowTitle: "Generate Claim/ Statement Document", onWindowTapClose: () { - // medicineController.clear(); - // quantityController.clear(); - // dosageController.clear(); - // timesDailyController.clear(); - // noDaysController.clear(); - // noRepeatsController.clear(); Navigator.pop(context); }, - windowBody: getWindowBody(), + windowBody: getWindowBody(screenWidth), ); } } diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/icd10_search_window.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/icd10_search_window.dart index 2e354256..9ce37354 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/icd10_search_window.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/icd10_search_window.dart @@ -1,5 +1,7 @@ -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_validation_services.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_objects/icd10_code.dart.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/list_builders/build_icd10_code_list.dart'; import 'package:flutter/material.dart'; @@ -21,12 +23,28 @@ class _ICD10SearchWindowState extends State { Widget getWindowBody() { return Column( children: [ - MIHTextField( + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: widget.icd10CodeController, - hintText: "Search Text", - editable: false, - required: false, + multiLineInput: false, + requiredText: true, + numberMode: true, + hintText: "ICD-10 Code Searched", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, ), + const SizedBox(height: 15), + Text( + "Search for ICD-10 Codes", + style: TextStyle( + color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), BuildICD10CodeList( icd10CodeController: widget.icd10CodeController, icd10codeList: widget.icd10codeList, diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_notes_list.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_notes_list.dart index 77c15290..94dc7368 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_notes_list.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_notes_list.dart @@ -2,9 +2,8 @@ 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_multiline_text_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.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_delete_message.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'; @@ -148,7 +147,7 @@ class _BuildNotesListState extends State { color: MzanziInnovationHub.of(context)!.theme.primaryColor(), ), - label: "Delete Document", + label: "Delete Note", labelBackgroundColor: MzanziInnovationHub.of(context)!.theme.successColor(), labelStyle: TextStyle( @@ -170,43 +169,62 @@ class _BuildNotesListState extends State { windowBody: Column( children: [ const SizedBox(height: 10.0), - MIHTextField( + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: businessNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "Office", - editable: false, - required: false, ), const SizedBox(height: 10.0), - MIHTextField( + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: userNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "Created By", - editable: false, - required: false, ), const SizedBox(height: 10.0), - MIHTextField( + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: dateController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "Created Date", - editable: false, - required: false, ), const SizedBox(height: 10.0), - MIHTextField( + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: noteTitleController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "Note Title", - editable: false, - required: false, ), const SizedBox(height: 10.0), - SizedBox( + MihTextFormField( height: 250, - child: MIHMLTextField( - controller: noteTextController, - hintText: "Note Details", - editable: false, - required: false, - ), + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: noteTextController, + multiLineInput: true, + requiredText: true, + readOnly: true, + hintText: "Note Details", ), + const SizedBox(height: 10.0), ], ), ), diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_consultation.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_consultation.dart index f07237e6..9787984c 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_consultation.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_consultation.dart @@ -1,13 +1,15 @@ 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_multiline_text_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.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_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; @@ -51,6 +53,7 @@ class _PatientConsultationState extends State { final doctorController = TextEditingController(); final ValueNotifier _counter = ValueNotifier(0); String endpoint = "${AppEnviroment.baseApiUrl}/notes/patients/"; + final _formKey = GlobalKey(); Future> fetchNotes(String endpoint) async { final response = await http.get(Uri.parse( @@ -67,7 +70,7 @@ class _PatientConsultationState extends State { } } - void addNotePopUp() { + void addNotePopUp(double width) { DateTime now = new DateTime.now(); DateTime date = new DateTime(now.year, now.month, now.day); var title = ""; @@ -92,101 +95,138 @@ class _PatientConsultationState extends State { titleController.clear(); noteTextController.clear(); }, - windowBody: Column( - children: [ - MIHTextField( - controller: officeController, - hintText: "Office", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: doctorController, - hintText: "Created By", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: dateController, - hintText: "Created Date", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: titleController, - hintText: "Note Title", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - SizedBox( - //width: 700, - height: 250, - child: MIHMLTextField( - controller: noteTextController, - hintText: "Note Details", - editable: true, - required: true, - ), - ), - SizedBox( - height: 15, - child: ValueListenableBuilder( - builder: (BuildContext context, int value, Widget? child) { - return Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - "$value", - style: TextStyle( - color: getNoteDetailLimitColor(), - ), - ), - const SizedBox(width: 5), - Text( - "/512", - style: TextStyle( - color: getNoteDetailLimitColor(), - ), - ), - ], - ); - }, - valueListenable: _counter, - ), - ), - const SizedBox(height: 15.0), - MihButton( - onPressed: () { - if (isFieldsFilled()) { - addPatientNoteAPICall(); - Navigator.pop(context); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); + windowBody: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: officeController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Office", + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: doctorController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Created By", + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: dateController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Created Date", + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: titleController, + multiLineInput: false, + requiredText: true, + hintText: "Note Title", + validator: (value) { + return MihValidationServices().isEmpty(value); }, - ); - } - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Add Note", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + ), + const SizedBox(height: 10.0), + MihTextFormField( + height: 250, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: noteTextController, + multiLineInput: true, + requiredText: true, + hintText: "Note Details", + validator: (value) { + return MihValidationServices().validateLength(value, 512); + }, + ), + SizedBox( + height: 15, + child: ValueListenableBuilder( + builder: + (BuildContext context, int value, Widget? child) { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "$value", + style: TextStyle( + color: getNoteDetailLimitColor(), + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 5), + Text( + "/512", + style: TextStyle( + color: getNoteDetailLimitColor(), + fontWeight: FontWeight.bold, + ), + ), + ], + ); + }, + valueListenable: _counter, + ), + ), + const SizedBox(height: 15.0), + MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + addPatientNoteAPICall(); + Navigator.pop(context); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + width: 300, + child: Text( + "Add Note", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], ), - ), - ], + ], + ), ), ), ); @@ -242,40 +282,6 @@ class _PatientConsultationState extends State { } } - List setIcons() { - if (widget.type == "personal") { - return [ - Text( - "Consultation Notes", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ), - ]; - } else { - return [ - Text( - "Consultation Notes", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ), - IconButton( - onPressed: () { - // addConsultationNotePopUp(); - addNotePopUp(); - }, - icon: Icon(Icons.add, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - ) - ]; - } - } - void successPopUp(String message) { showDialog( context: context, @@ -320,13 +326,14 @@ class _PatientConsultationState 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( @@ -384,7 +391,7 @@ class _PatientConsultationState extends State { MzanziInnovationHub.of(context)!.theme.successColor(), onTap: () { // addConsultationNotePopUp(); - addNotePopUp(); + addNotePopUp(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 310c4769..320b3fd6 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 @@ -1,9 +1,10 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_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_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_text_form_field.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'; @@ -37,76 +38,126 @@ class _PatientInfoState extends State { final medAidController = TextEditingController(); final medMainMemController = TextEditingController(); final medAidCodeController = TextEditingController(); - double textFieldWidth = 400.0; + final _formKey = GlobalKey(); + double textFieldWidth = 500; late String medAid; Widget getPatientDetailsField() { - return Wrap( - spacing: 15, - runSpacing: 10, - children: [ - SizedBox( - width: textFieldWidth, - child: MIHTextField( + return Center( + child: Wrap( + spacing: 15, + runSpacing: 10, + children: [ + SizedBox( + width: textFieldWidth, + child: MihTextFormField( + // width: textFieldWidth, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: idController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "ID No.", - editable: false, - required: false), - ), - SizedBox( - width: textFieldWidth, - child: MIHTextField( + // validator: (value) { + // return MihValidationServices().isEmpty(value); + // }, + ), + ), + SizedBox( + width: textFieldWidth, + child: MihTextFormField( + // width: textFieldWidth, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: fnameController, - hintText: "Name", - editable: false, - required: false), - ), - SizedBox( - width: textFieldWidth, - child: MIHTextField( + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "First Name", + ), + ), + SizedBox( + width: textFieldWidth, + child: MihTextFormField( + // width: textFieldWidth, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: lnameController, + multiLineInput: false, + requiredText: true, hintText: "Surname", - editable: false, - required: false), - ), - SizedBox( - width: textFieldWidth, - child: MIHTextField( + readOnly: true, + ), + ), + SizedBox( + width: textFieldWidth, + child: MihTextFormField( + // width: textFieldWidth, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: cellController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "Cell No.", - editable: false, - required: false), - ), - SizedBox( - width: textFieldWidth, - child: MIHTextField( + ), + ), + SizedBox( + width: textFieldWidth, + child: MihTextFormField( + // width: textFieldWidth, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: emailController, + multiLineInput: false, + requiredText: true, + readOnly: true, hintText: "Email", - editable: false, - required: false), - ), - SizedBox( - width: textFieldWidth, - child: MIHTextField( + ), + ), + SizedBox( + width: textFieldWidth, + child: MihTextFormField( + // width: textFieldWidth, + height: 100, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), controller: addressController, + multiLineInput: true, + requiredText: true, + readOnly: true, hintText: "Address", - editable: false, - required: false), - ), - ], + ), + ), + ], + ), ); } Widget getMedAidDetailsFields() { List medAidDet = []; - medAidDet.add(SizedBox( - width: textFieldWidth, - child: MIHTextField( + 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, hintText: "Medical Aid", - editable: false, - required: false), - )); + ), + ), + ); bool req; if (medAid == "Yes") { req = true; @@ -118,67 +169,88 @@ class _PatientInfoState extends State { visible: req, child: SizedBox( width: textFieldWidth, - child: MIHTextField( - controller: medMainMemController, - hintText: "Main Member", - editable: false, - required: false), + child: MihTextFormField( + // width: textFieldWidth, + fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: medMainMemController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Main Member", + ), ), ), - //const SizedBox(height: 10.0), Visibility( visible: req, child: SizedBox( width: textFieldWidth, - child: MIHTextField( - controller: medNoController, - hintText: "No.", - editable: false, - required: false), + child: MihTextFormField( + // width: textFieldWidth, + fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: medNoController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "No.", + ), ), ), - //const SizedBox(height: 10.0), Visibility( visible: req, child: SizedBox( width: textFieldWidth, - child: MIHTextField( - controller: medAidCodeController, - hintText: "Code", - editable: false, - required: false), + child: MihTextFormField( + // width: textFieldWidth, + fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: medAidCodeController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Code", + ), + ), + ), + Visibility( + visible: req, + child: SizedBox( + child: MihTextFormField( + // width: textFieldWidth, + fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: medNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Name", + ), ), ), - //const SizedBox(height: 10.0), Visibility( visible: req, child: SizedBox( width: textFieldWidth, - child: MIHTextField( - controller: medNameController, - hintText: "Name", - editable: false, - required: false), + child: MihTextFormField( + // width: textFieldWidth, + fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: medSchemeController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Plan", + ), ), ), - //const SizedBox(height: 10.0), - Visibility( - visible: req, - child: SizedBox( - width: textFieldWidth, - child: MIHTextField( - controller: medSchemeController, - hintText: "Plan", - editable: false, - required: false), - ), - ), - //), ]); - return Wrap( - spacing: 10, - runSpacing: 10, - children: medAidDet, + return Center( + child: Wrap( + spacing: 10, + runSpacing: 10, + children: medAidDet, + ), ); } @@ -232,25 +304,50 @@ class _PatientInfoState extends State { @override Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; return MihPackageToolBody( borderOn: false, innerHorizontalPadding: 10, - bodyItem: getBody(), + bodyItem: getBody(screenWidth), ); } - Widget getBody() { + Widget getBody(double width) { return Stack( children: [ MihSingleChildScroll( child: Column( + mainAxisAlignment: MainAxisAlignment.center, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - //crossAxisAlignment: , - children: [ - Text( - "Personal Details", + MihForm( + formKey: _formKey, + formFields: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + //crossAxisAlignment: , + children: [ + Text( + "Personal", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + ), + ), + ]), + Divider( + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor()), + const SizedBox(height: 10), + getPatientDetailsField(), + const SizedBox(height: 10), + Center( + child: Text( + "Medical Aid", textAlign: TextAlign.center, style: TextStyle( fontSize: 25, @@ -260,25 +357,15 @@ class _PatientInfoState extends State { .secondaryColor(), ), ), - ]), - const SizedBox(height: 10), - getPatientDetailsField(), - const SizedBox(height: 10), - Text( - "Medical Aid Details", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), + ), + Divider( + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor()), + const SizedBox(height: 10), + getMedAidDetailsFields(), + ], ), - Divider( - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor()), - const SizedBox(height: 10), - getMedAidDetailsFields(), ], ), ), 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 4b9fdc32..4afaabfa 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 @@ -1,14 +1,16 @@ 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_inputs_and_buttons/mih_text_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_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_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_success_message.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; @@ -49,6 +51,7 @@ class _AddPatientState extends State { //late bool medRequired; final ValueNotifier medRequired = ValueNotifier(false); final FocusNode _focusNode = FocusNode(); + final _formKey = GlobalKey(); bool isFieldsFilled() { if (medRequired.value) { @@ -158,169 +161,288 @@ class _AddPatientState extends State { } } - Widget displayForm() { - return MihSingleChildScroll( - child: Column( - children: [ - Text( - "Personal Details", - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 22.0, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - Divider( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - const SizedBox(height: 10.0), - MIHTextField( - controller: idController, - hintText: "13 digit ID Number or Passport", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: fnameController, - hintText: "First Name", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: lnameController, - hintText: "Last Name", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: cellController, - hintText: "Cell Number", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: emailController, - hintText: "Email", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: addressController, - hintText: "Address", - editable: true, - required: true, - ), - const SizedBox(height: 15.0), - Text( - "Medical Aid Details", - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 22.0, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - Divider( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: medAidController, - hintText: "Medical Aid", - editable: true, - enableSearch: false, - // onSelect: (_) { - // isRequired(); - // }, - required: true, - dropdownOptions: const ["Yes", "No"], - ), - ValueListenableBuilder( - valueListenable: medRequired, - builder: (BuildContext context, bool value, Widget? child) { - return Visibility( - visible: value, - child: Column( + Widget displayForm(double width) { + return SingleChildScrollView( + child: Padding( + padding: MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ - const SizedBox(height: 10.0), - MIHDropdownField( - controller: medMainMemController, - hintText: "Main Member", - editable: value, - required: value, - enableSearch: false, - dropdownOptions: const ["Yes", "No"], - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: medNoController, - hintText: "Medical Aid No.", - editable: value, - required: value, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: medAidCodeController, - hintText: "Medical Aid Code", - editable: value, - required: value, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: medNameController, - hintText: "Medical Aid Name", - editable: value, - required: value, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: medSchemeController, - hintText: "Medical Aid Plan", - editable: value, - required: value, + Text( + "Personal", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 25.0, + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + ), ), ], ), - ); - }, - ), - const SizedBox(height: 30.0), - MihButton( - onPressed: () { - submitForm(); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Add", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + Divider( + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor()), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: idController, + multiLineInput: false, + requiredText: true, + hintText: "ID No.", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: fnameController, + multiLineInput: false, + requiredText: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: lnameController, + multiLineInput: false, + requiredText: true, + hintText: "Surname", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: cellController, + multiLineInput: false, + requiredText: true, + hintText: "Cell No.", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: emailController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Email", + validator: (value) { + return MihValidationServices().validateEmail(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + height: 100, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: addressController, + multiLineInput: true, + requiredText: true, + hintText: "Address", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 15.0), + Center( + child: Text( + "Medical Aid Details", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 25.0, + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + ), + ), + ), + Divider( + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor()), + const SizedBox(height: 10.0), + MIHDropdownField( + controller: medAidController, + hintText: "Medical Aid", + editable: true, + required: true, + enableSearch: false, + dropdownOptions: const ["Yes", "No"], + ), + ValueListenableBuilder( + valueListenable: medRequired, + builder: (BuildContext context, bool value, Widget? child) { + return Visibility( + visible: value, + child: Column( + children: [ + const SizedBox(height: 10.0), + MIHDropdownField( + controller: medMainMemController, + hintText: "Main Member", + editable: value, + required: value, + enableSearch: false, + dropdownOptions: const ["Yes", "No"], + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: medNoController, + multiLineInput: false, + requiredText: true, + hintText: "No.", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: medAidCodeController, + multiLineInput: false, + requiredText: true, + hintText: "Code", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: medNameController, + multiLineInput: false, + requiredText: true, + hintText: "Name", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: medSchemeController, + multiLineInput: false, + requiredText: true, + hintText: "Plan", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + ], + ), + ); + }, + ), + const SizedBox(height: 20.0), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(); + } 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, + ), + ), + ), + ), + const SizedBox(height: 20.0), + ], ), - ), - ], + ], + ), ), ); } void submitForm() { - if (isFieldsFilled()) { - addPatientAPICall(); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } + addPatientAPICall(); } MIHAction getActionButton() { @@ -348,9 +470,9 @@ class _AddPatientState extends State { ); } - MIHBody getBody() { + MIHBody getBody(double width) { return MIHBody( - borderOn: true, + borderOn: false, bodyItems: [ KeyboardListener( focusNode: _focusNode, @@ -358,10 +480,14 @@ class _AddPatientState extends State { onKeyEvent: (event) async { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.enter) { - submitForm(); + if (_formKey.currentState!.validate()) { + submitForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } } }, - child: displayForm(), + child: displayForm(width), ), ], ); @@ -401,12 +527,12 @@ class _AddPatientState extends State { @override Widget build(BuildContext context) { - print("Add Patient"); + double screenWidth = MediaQuery.of(context).size.width; return MIHLayoutBuilder( actionButton: getActionButton(), header: getHeader(), secondaryActionButton: null, - body: getBody(), + body: getBody(screenWidth), actionDrawer: null, secondaryActionDrawer: null, bottomNavBar: null, 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 81ad520a..63dd4f86 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 @@ -1,13 +1,16 @@ 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_inputs_and_buttons/mih_text_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_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'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; @@ -49,6 +52,7 @@ class _EditPatientState extends State { final docOfficeIdApiUrl = "${AppEnviroment.baseApiUrl}/users/profile/"; final apiUrlEdit = "${AppEnviroment.baseApiUrl}/patients/update/"; final apiUrlDelete = "${AppEnviroment.baseApiUrl}/patients/delete/"; + final _formKey = GlobalKey(); late int futureDocOfficeId; late String userEmail; @@ -371,200 +375,288 @@ class _EditPatientState extends State { } } - Widget displayForm() { + Widget displayForm(double width) { return SingleChildScrollView( - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Personal Details", - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 22.0, - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - // IconButton( - // icon: const Icon(Icons.delete), - // color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - // //alignment: Alignment.topRight, - // onPressed: () { - // deletePatientPopUp(); - // }, - // ), - ], - ), - Divider( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - const SizedBox(height: 10.0), - MIHTextField( - controller: idController, - hintText: "13 digit ID Number or Passport", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: fnameController, - hintText: "First Name", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: lnameController, - hintText: "Last Name", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: cellController, - hintText: "Cell Number", - editable: true, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: emailController, - hintText: "Email", - editable: false, - required: true, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: addressController, - hintText: "Address", - editable: true, - required: true, - ), - const SizedBox(height: 15.0), - Text( - "Medical Aid Details", - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 22.0, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - Divider( - color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - const SizedBox(height: 10.0), - MIHDropdownField( - controller: medAidController, - hintText: "Medical Aid", - // onSelect: (selected) { - // if (selected == "Yes") { - // setState(() { - // medRequired = true; - // }); - // } else { - // setState(() { - // medRequired = false; - // }); - // } - // }, - editable: true, - required: true, - enableSearch: false, - dropdownOptions: const ["Yes", "No"], - ), - ValueListenableBuilder( - valueListenable: medRequired, - builder: (BuildContext context, bool value, Widget? child) { - return Visibility( - visible: value, - child: Column( + child: Padding( + padding: MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ - const SizedBox(height: 10.0), - MIHDropdownField( - controller: medMainMemController, - hintText: "Main Member.", - editable: value, - required: value, - enableSearch: false, - dropdownOptions: const ["Yes", "No"], - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: medNoController, - hintText: "Medical Aid No.", - editable: value, - required: value, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: medAidCodeController, - hintText: "Medical Aid Code", - editable: value, - required: value, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: medNameController, - hintText: "Medical Aid Name", - editable: value, - required: value, - ), - const SizedBox(height: 10.0), - MIHTextField( - controller: medSchemeController, - hintText: "Medical Aid Plan", - editable: value, - required: value, + Text( + "Personal", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 25.0, + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + ), ), ], ), - ); - }, - ), - const SizedBox(height: 30.0), - MihButton( - onPressed: () { - submitForm(); - }, - buttonColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MzanziInnovationHub.of(context)!.theme.primaryColor(), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + Divider( + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor()), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: idController, + multiLineInput: false, + requiredText: true, + hintText: "ID No.", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: fnameController, + multiLineInput: false, + requiredText: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: lnameController, + multiLineInput: false, + requiredText: true, + hintText: "Surname", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: cellController, + multiLineInput: false, + requiredText: true, + hintText: "Cell No.", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: emailController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Email", + validator: (value) { + return MihValidationServices().validateEmail(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + height: 100, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: addressController, + multiLineInput: true, + requiredText: true, + hintText: "Address", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 15.0), + Center( + child: Text( + "Medical Aid Details", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 25.0, + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + ), + ), + ), + Divider( + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor()), + const SizedBox(height: 10.0), + MIHDropdownField( + controller: medAidController, + hintText: "Medical Aid", + editable: true, + required: true, + enableSearch: false, + dropdownOptions: const ["Yes", "No"], + ), + ValueListenableBuilder( + valueListenable: medRequired, + builder: (BuildContext context, bool value, Widget? child) { + return Visibility( + visible: value, + child: Column( + children: [ + const SizedBox(height: 10.0), + MIHDropdownField( + controller: medMainMemController, + hintText: "Main Member", + editable: value, + required: value, + enableSearch: false, + dropdownOptions: const ["Yes", "No"], + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: medNoController, + multiLineInput: false, + requiredText: true, + hintText: "No.", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: medAidCodeController, + multiLineInput: false, + requiredText: true, + hintText: "Code", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: medNameController, + multiLineInput: false, + requiredText: true, + hintText: "Name", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + controller: medSchemeController, + multiLineInput: false, + requiredText: true, + hintText: "Plan", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + ], + ), + ); + }, + ), + const SizedBox(height: 20.0), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(height: 20.0), + ], ), - ), - ], + ], + ), ), ); } void submitForm() { - if (isFieldsFilled()) { - if (!medRequired.value) { - setState(() { - medMainMemController.text = ""; - medNoController.text = ""; - medAidCodeController.text = ""; - medNameController.text = ""; - medSchemeController.text = ""; - }); - } - updatePatientApiCall(); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } + updatePatientApiCall(); } MIHAction getActionButton() { @@ -592,9 +684,9 @@ class _EditPatientState extends State { ); } - MIHBody getBody() { + MIHBody getBody(double width) { return MIHBody( - borderOn: true, + borderOn: false, bodyItems: [ KeyboardListener( focusNode: _focusNode, @@ -602,10 +694,14 @@ class _EditPatientState extends State { onKeyEvent: (event) async { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.enter) { - submitForm(); + if (_formKey.currentState!.validate()) { + submitForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } } }, - child: displayForm(), + child: displayForm(width), ), ], ); @@ -665,61 +761,12 @@ class _EditPatientState extends State { actionButton: getActionButton(), header: getHeader(), secondaryActionButton: null, - body: getBody(), + body: getBody(width), actionDrawer: null, secondaryActionDrawer: null, bottomNavBar: null, pullDownToRefresh: false, onPullDown: () async {}, ); - // return Scaffold( - // // appBar: const MIHAppBar( - // // barTitle: "Edit Patient", - // // propicFile: null, - // // ), - // body: SafeArea( - // child: Stack( - // children: [ - // KeyboardListener( - // focusNode: _focusNode, - // autofocus: true, - // onKeyEvent: (event) async { - // if (event is KeyDownEvent && - // event.logicalKey == LogicalKeyboardKey.enter) { - // submitForm(); - // } - // }, - // child: displayForm(), - // ), - // Positioned( - // top: 10, - // left: 5, - // width: 50, - // height: 50, - // child: IconButton( - // onPressed: () { - // Navigator.of(context).pop(); - // }, - // icon: const Icon(Icons.arrow_back), - // ), - // ), - // Positioned( - // top: 10, - // right: 5, - // width: 50, - // height: 50, - // child: IconButton( - // icon: const Icon(Icons.delete), - // color: - // MzanziInnovationHub.of(context)!.theme.secondaryColor(), - // //alignment: Alignment.topRight, - // onPressed: () { - // deletePatientPopUp(); - // }, - // )) - // ], - // ), - // ), - // ); } } diff --git a/Frontend/pubspec.yaml b/Frontend/pubspec.yaml index 83c9a961..65884909 100644 --- a/Frontend/pubspec.yaml +++ b/Frontend/pubspec.yaml @@ -77,6 +77,7 @@ dependencies: share_plus: ^10.1.4 app_settings: ^6.1.1 animated_button: ^0.3.1 + pwa_install: ^0.0.6 dev_dependencies: flutter_test: @@ -84,7 +85,7 @@ dev_dependencies: build_runner: ^2.4.8 - build_web_compilers: ^3.2.7 + build_web_compilers: ^4.1.5 # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your diff --git a/Frontend/web/index.html b/Frontend/web/index.html index 2b93b190..699985ae 100644 --- a/Frontend/web/index.html +++ b/Frontend/web/index.html @@ -1,10 +1,14 @@ - + + + + - + @@ -27,9 +31,40 @@ - - - + + + + + @@ -248,8 +294,11 @@ - - - + + + - \ No newline at end of file + + + \ No newline at end of file