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 20e8ae0e..26108ce5 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 @@ -11,6 +11,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_image_display.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; class PackageToolOne extends StatefulWidget { const PackageToolOne({super.key}); @@ -25,6 +26,8 @@ class _PackageToolOneState extends State { PlatformFile? imageFile; TextEditingController _fileNameController = TextEditingController(); TextEditingController _imagefileController = TextEditingController(); + TextEditingController _searchController = TextEditingController(); + final FocusNode searchFocusNode = FocusNode(); void showTestFullWindow() { showDialog( context: context, @@ -80,6 +83,23 @@ class _PackageToolOneState extends State { ); } + @override + Widget build(BuildContext context) { + return MihPackageToolBody( + borderOn: true, + bodyItem: getBody(), + ); + } + + @override + void dispose() { + _fileNameController.dispose(); + _imagefileController.dispose(); + _searchController.dispose(); + searchFocusNode.dispose(); + super.dispose(); + } + @override void initState() { super.initState(); @@ -90,14 +110,6 @@ class _PackageToolOneState extends State { }); } - @override - Widget build(BuildContext context) { - return MihPackageToolBody( - borderOn: true, - bodyItem: getBody(), - ); - } - Widget getBody() { return Stack( children: [ @@ -123,7 +135,24 @@ class _PackageToolOneState extends State { ), ], ), - const SizedBox(height: 10), + 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"); diff --git a/Frontend/lib/mih_components/mih_package_components/mih_search_bar.dart b/Frontend/lib/mih_components/mih_package_components/mih_search_bar.dart new file mode 100644 index 00000000..0be979f2 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_search_bar.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +class MihSearchBar extends StatefulWidget { + final TextEditingController controller; + final String hintText; + final IconData prefixIcon; + final IconData? prefixAltIcon; + final List? suffixTools; + final double? width; + final double? height; + final Color fillColor; + final Color hintColor; + final void Function()? onPrefixIconTap; + final void Function()? onClearIconTap; + final double? elevation; + final FocusNode searchFocusNode; + + const MihSearchBar({ + Key? key, + required this.controller, + required this.hintText, + required this.prefixIcon, + this.prefixAltIcon, + this.suffixTools, + this.width, + this.height, + required this.fillColor, + required this.hintColor, + required this.onPrefixIconTap, + this.onClearIconTap, + this.elevation, + required this.searchFocusNode, + }) : super(key: key); + + @override + State createState() => _MihSearchBarState(); +} + +class _MihSearchBarState extends State { + bool _showClearIcon = false; + + Widget getPrefixIcon() { + if (_showClearIcon) { + // If the clear icon is shown and an alternative prefix icon is provided, use it + return widget.prefixAltIcon != null + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Icon( + widget.prefixAltIcon, + color: widget.hintColor, + size: 35, + ), + ) + : Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Icon( + Icons.search, + color: widget.hintColor, + size: 35, + ), + ); // Default to search icon if no alt icon + } else { + // Return the primary prefix icon or the alternative if provided + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Icon( + Icons.search, + color: widget.hintColor, + size: 35, + ), + ); + } + } + + @override + void initState() { + super.initState(); + // 1. Add the listener to the controller + widget.controller.addListener(_updateClearIconVisibility); + // 2. Initialize the clear icon visibility based on the current text + _updateClearIconVisibility(); + } + + @override + void dispose() { + widget.controller.removeListener(_updateClearIconVisibility); + super.dispose(); + } + + void _updateClearIconVisibility() { + if (!mounted) { + return; + } + final bool shouldShow = widget.controller.text.isNotEmpty; + // Only call setState if the visibility state actually changes + if (_showClearIcon != shouldShow) { + setState(() { + _showClearIcon = shouldShow; + }); + } + } + + @override + Widget build(BuildContext context) { + return Material( + elevation: widget.elevation ?? 4.0, // Use provided elevation or default + borderRadius: BorderRadius.circular(30.0), + color: widget.fillColor, + child: AnimatedContainer( + // Keep AnimatedContainer for width/height transitions + width: widget.width, + height: widget.height ?? 50, + duration: const Duration(milliseconds: 300), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30.0), + ), + child: Theme( + data: Theme.of(context).copyWith( + textSelectionTheme: TextSelectionThemeData( + selectionColor: widget.hintColor.withValues(alpha: 0.3), + selectionHandleColor: widget.hintColor, + ), + ), + child: TextField( + controller: widget.controller, // Assign the controller + focusNode: widget.searchFocusNode, + style: TextStyle( + color: widget.hintColor, + fontWeight: FontWeight.w600, + ), + cursorColor: widget.hintColor, + decoration: InputDecoration( + hintText: widget.hintText, + hintStyle: TextStyle( + color: widget.hintColor, + fontWeight: FontWeight.bold, + ), + border: InputBorder.none, + contentPadding: + const EdgeInsets.symmetric(horizontal: 20.0, vertical: 12.0), + prefixIcon: GestureDetector( + onTap: widget.onPrefixIconTap, + child: getPrefixIcon(), + ), + suffixIcon: Row( + // Use a Row for multiple suffix icons + mainAxisSize: MainAxisSize.min, + children: [ + // Optional suffix tools + if (widget.suffixTools != null) ...widget.suffixTools!, + // Clear Icon (conditionally visible) + if (_showClearIcon) // Only show if input is not empty + IconButton( + icon: Icon(Icons.clear, + color: widget.hintColor), // Clear icon + onPressed: widget.onClearIconTap ?? + () { + widget.controller.clear(); + // No need for setState here, _updateClearIconVisibility will handle it + }, + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/Frontend/lib/mih_packages/mih_home/mih_home_legacy.dart b/Frontend/lib/mih_packages/mih_home/mih_home_legacy.dart index 18863d5a..940aa5a4 100644 --- a/Frontend/lib/mih_packages/mih_home/mih_home_legacy.dart +++ b/Frontend/lib/mih_packages/mih_home/mih_home_legacy.dart @@ -3,7 +3,9 @@ import 'dart:convert'; // import 'dart:convert'; import 'package:flutter_speed_dial/flutter_speed_dial.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_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_objects/patients.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -15,7 +17,6 @@ import 'package:supertokens_flutter/http.dart' as http; import "package:universal_html/html.dart" as html; import '../../mih_apis/mih_location_api.dart'; -import '../../mih_components/mih_inputs_and_buttons/mih_search_input.dart'; import '../../mih_components/mih_layout/mih_action.dart'; import 'components/mih_app_drawer.dart'; import '../../mih_components/mih_layout/mih_body.dart'; @@ -1082,16 +1083,22 @@ class _MIHHomeLegacyState extends State { } }, child: SizedBox( - child: MIHSearchField( + child: MihSearchBar( controller: searchController, - hintText: "Search Mzansi Packages", - required: false, - editable: true, - onTap: () { + hintText: "Ask Mzansi", + prefixIcon: Icons.search, + prefixAltIcon: MihIcons.mzansiAi, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + print("Search Text: ${searchController.text}"); setState(() { appSearch = searchController.text; }); }, + searchFocusNode: FocusNode(), ), ), ), diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index 879b42e1..26cf0922 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -1,7 +1,8 @@ import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_search_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_icons.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_search_bar.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/business.dart'; @@ -43,6 +44,7 @@ class _MihBusinessHomeState extends State double packageSize = 200; late final AnimationController _marqueeController; late final ScrollController _scrollController; + final FocusNode _searchFocusNode = FocusNode(); final String maintenanceMsg = "\tHeads up! We're doing maintenance on Thur, 15 May 2025 at 10 PM (CAT). MIH may be unavailable briefly."; @@ -164,6 +166,9 @@ class _MihBusinessHomeState extends State super.dispose(); searchController.removeListener(searchPackage); searchController.dispose(); + _marqueeController.dispose(); + _scrollController.dispose(); + _searchFocusNode.dispose(); } @override @@ -199,40 +204,22 @@ class _MihBusinessHomeState extends State return MihSingleChildScroll( child: Column( children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - Flexible( - flex: 4, - child: SizedBox( - child: MIHSearchField( - controller: searchController, - hintText: "Search MIH Packages", - required: false, - editable: true, - onTap: () { - setState(() {}); - }, - ), - ), - ), - Flexible( - flex: 1, - child: IconButton( - //padding: const EdgeInsets.all(0), - onPressed: () { - setState(() { - searchController.clear(); - }); - }, - icon: const Icon( - Icons.filter_alt_off, - size: 30, - ), - ), - ), - ], + const SizedBox(height: 10), + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: searchController, + hintText: "Ask Mzansi", + prefixIcon: Icons.search, + prefixAltIcon: MihIcons.mzansiAi, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + print("Search Text: ${searchController.text}"); + }, + searchFocusNode: _searchFocusNode, + ), ), const SizedBox(height: 10), ValueListenableBuilder( diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index beaa6271..8da7e898 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -1,8 +1,9 @@ import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_search_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_icons.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_tile.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.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/business.dart'; @@ -51,6 +52,7 @@ class _MihPersonalHomeState extends State double packageSize = 200; late final AnimationController _marqueeController; late final ScrollController _scrollController; + final FocusNode _searchFocusNode = FocusNode(); final String maintenanceMsg = "\tHeads up! We're doing maintenance on Thur, 15 May 2025 at 10 PM (CAT). MIH may be unavailable briefly."; @@ -206,6 +208,7 @@ class _MihPersonalHomeState extends State super.dispose(); searchController.removeListener(searchPackage); searchController.dispose(); + _searchFocusNode.dispose(); _marqueeController.dispose(); _scrollController.dispose(); } @@ -244,38 +247,22 @@ class _MihPersonalHomeState extends State return MihSingleChildScroll( child: Column( children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - Flexible( - flex: 4, - child: SizedBox( - child: MIHSearchField( - controller: searchController, - hintText: "Search MIH Packages", - required: false, - editable: true, - onTap: () {}, - ), - ), - ), - Flexible( - flex: 1, - child: IconButton( - //padding: const EdgeInsets.all(0), - onPressed: () { - setState(() { - searchController.clear(); - }); - }, - icon: const Icon( - Icons.filter_alt_off, - size: 30, - ), - ), - ), - ], + const SizedBox(height: 10), + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: searchController, + hintText: "Ask Mzansi", + prefixIcon: Icons.search, + prefixAltIcon: MihIcons.mzansiAi, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + print("Search Text: ${searchController.text}"); + }, + searchFocusNode: _searchFocusNode, + ), ), const SizedBox(height: 10), ValueListenableBuilder( diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart index b13d21d5..822cf061 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart @@ -1,9 +1,8 @@ import 'dart:convert'; - import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_search_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_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.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'; @@ -29,6 +28,7 @@ class _MihBusinessUserSearchState extends State { final FocusNode _focusNode = FocusNode(); final TextEditingController searchController = TextEditingController(); late Future> userSearchResults; + final FocusNode _searchFocusNode = FocusNode(); String userSearch = ""; String errorCode = ""; @@ -89,16 +89,25 @@ class _MihBusinessUserSearchState extends State { userSearchResults = fetchUsers("abc"); } + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + _searchFocusNode.dispose(); + } + @override Widget build(BuildContext context) { + final Size size = MediaQuery.sizeOf(context); + final double width = size.width; return MihPackageToolBody( borderOn: false, innerHorizontalPadding: 10, - bodyItem: getBody(), + bodyItem: getBody(width), ); } - Widget getBody() { + Widget getBody(double width) { return MihSingleChildScroll( child: KeyboardListener( focusNode: _focusNode, @@ -110,16 +119,21 @@ class _MihBusinessUserSearchState extends State { } }, child: Column(mainAxisSize: MainAxisSize.max, children: [ - MIHSearchField( - controller: searchController, - hintText: "Username or Email Search", - required: true, - editable: true, - onTap: () { - submitUserForm(); - }, + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: searchController, + hintText: "Search Users", + prefixIcon: Icons.search, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + submitUserForm(); + }, + searchFocusNode: _searchFocusNode, + ), ), - //spacer const SizedBox(height: 10), FutureBuilder( future: userSearchResults, diff --git a/Frontend/lib/mih_packages/mzansi_profile/manage_business/manage_business_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/manage_business/manage_business_profile.dart index 152d7308..977ed57e 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/manage_business/manage_business_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/manage_business/manage_business_profile.dart @@ -3,10 +3,9 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import '../../../main.dart'; import 'package:supertokens_flutter/http.dart' as http; - -import '../../../mih_components/mih_inputs_and_buttons/mih_search_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 +34,7 @@ class ManageBusinessProfile extends StatefulWidget { class _ManageBusinessProfileState extends State { final FocusNode _focusNode = FocusNode(); + final FocusNode _searchFocusNode = FocusNode(); final baseAPI = AppEnviroment.baseApiUrl; final TextEditingController searchController = TextEditingController(); @@ -179,7 +179,7 @@ class _ManageBusinessProfileState extends State { } } - Widget userSearchView() { + Widget userSearchView(double width) { return KeyboardListener( focusNode: _focusNode, autofocus: true, @@ -198,15 +198,21 @@ class _ManageBusinessProfileState extends State { Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), const SizedBox(height: 10), - MIHSearchField( - controller: searchController, - hintText: "Username or Email Search", - required: true, - editable: true, - onTap: () { - submitUserForm(); - }, + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: searchController, + hintText: "Ask Mzansi", + prefixIcon: Icons.search, + fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + print("Search Text: ${searchController.text}"); + }, + searchFocusNode: _searchFocusNode, + ), ), + //spacer const SizedBox(height: 10), FutureBuilder( @@ -274,7 +280,7 @@ class _ManageBusinessProfileState extends State { ); } - Widget showSelection(int selectionIndex) { + Widget showSelection(int selectionIndex, double width, [double? height]) { // if (selectionIndex == 0) { // return BusinessDetails(arguments: widget.arguments); // } else @@ -283,7 +289,7 @@ class _ManageBusinessProfileState extends State { } else if (selectionIndex == 1) { return employeesview(); } else { - return userSearchView(); + return userSearchView(width); } } @@ -412,11 +418,11 @@ class _ManageBusinessProfileState extends State { ); } - MIHBody getBody() { + MIHBody getBody(double width) { return MIHBody( borderOn: true, bodyItems: [ - showSelection(selectionIndex), + showSelection(selectionIndex, width), ], ); } @@ -425,6 +431,7 @@ class _ManageBusinessProfileState extends State { void dispose() { searchController.dispose(); _focusNode.dispose(); + _searchFocusNode.dispose(); super.dispose(); } @@ -437,6 +444,8 @@ class _ManageBusinessProfileState extends State { @override Widget build(BuildContext context) { + final Size size = MediaQuery.sizeOf(context); + final double width = size.width; return SwipeDetector( onSwipeLeft: (offset) { if (selectionIndex < 2) { @@ -458,7 +467,7 @@ class _ManageBusinessProfileState extends State { actionButton: getActionButton(), secondaryActionButton: null, header: getHeader(), - body: getBody(), + body: getBody(width), actionDrawer: null, secondaryActionDrawer: null, bottomNavBar: null, 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 16b0a4a1..c4daf39e 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart @@ -3,13 +3,13 @@ import 'package:mzansi_innovation_hub/main.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_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_search_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_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_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'; @@ -35,6 +35,7 @@ class _MihCardsState extends State { final TextEditingController _nicknameController = TextEditingController(); final TextEditingController cardNumberController = TextEditingController(); final TextEditingController cardSearchController = TextEditingController(); + final FocusNode searchFocusNode = FocusNode(); late Future> cardList; List listOfCards = []; //bool showSelectedCardType = false; @@ -253,6 +254,7 @@ class _MihCardsState extends State { cardSearchController.dispose(); searchShopName.dispose(); _nicknameController.dispose(); + searchFocusNode.dispose(); shopName.dispose(); super.dispose(); } @@ -267,45 +269,36 @@ class _MihCardsState extends State { @override Widget build(BuildContext context) { + final Size size = MediaQuery.sizeOf(context); + final double width = size.width; return MihPackageToolBody( borderOn: false, - bodyItem: getBody(), + bodyItem: getBody(width), ); } - Widget getBody() { + Widget getBody(double width) { return Stack( children: [ MihSingleChildScroll( child: Column( children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Flexible( - flex: 4, - child: SizedBox( - height: 50, - child: MIHSearchField( - controller: cardSearchController, - hintText: "Shop Name", - required: false, - editable: true, - onTap: () {}, - ), - ), - ), - Flexible( - flex: 1, - child: IconButton( - onPressed: () { - FocusScope.of(context).unfocus(); - cardSearchController.clear(); - }, - icon: const Icon(Icons.filter_alt_off), - ), - ), - ], + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: cardSearchController, + hintText: "Search Cards", + // prefixIcon: Icons.search, + prefixIcon: Icons.search, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + print("Search Icon Pressed: ${cardSearchController.text}"); + }, + searchFocusNode: searchFocusNode, + ), ), const SizedBox(height: 10), FutureBuilder( diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart b/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart index cc762980..64a7c3f9 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart @@ -1,8 +1,8 @@ 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_search_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_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.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'; @@ -35,11 +35,12 @@ class MihPatientSearch extends StatefulWidget { class _MihPatientSearchState extends State { TextEditingController _mihPatientSearchController = TextEditingController(); final FocusNode _focusNode = FocusNode(); + final FocusNode _searchFocusNode = FocusNode(); String _mihPatientSearchString = ""; String baseUrl = AppEnviroment.baseApiUrl; late Future> _mihPatientSearchResults; - Widget getPatientSearch() { + Widget getPatientSearch(double width) { return MihSingleChildScroll( child: KeyboardListener( focusNode: _focusNode, @@ -54,39 +55,30 @@ class _MihPatientSearchState extends State { } }, child: Column(mainAxisSize: MainAxisSize.max, children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - flex: 1, - child: MIHSearchField( - controller: _mihPatientSearchController, - hintText: "ID or Medical Aid No. Search", - required: false, - editable: true, - onTap: () { - // submitPatientForm(); - submitPatientSearch(); - //To-Do: Implement the search function - // print("To-Do: Implement the search function"); - }, - ), - ), - IconButton( - onPressed: () { - setState(() { - _mihPatientSearchController.clear(); - _mihPatientSearchString = ""; - }); - submitPatientSearch(); - //To-Do: Implement the search function - // print("To-Do: Implement the search function"); - }, - icon: const Icon( - Icons.filter_alt_off, - size: 25, - )) - ], + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: _mihPatientSearchController, + hintText: "Search by ID or Medical Aid No.", + prefixIcon: Icons.search, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + submitPatientSearch(); + print("Search Text: ${_mihPatientSearchController.text}"); + }, + onClearIconTap: () { + setState(() { + _mihPatientSearchController.clear(); + _mihPatientSearchString = ""; + }); + submitPatientSearch(); + //To-Do: Implement the search function + // print("To-Do: Implement the search function"); + }, + searchFocusNode: _searchFocusNode, + ), ), //spacer const SizedBox(height: 10), @@ -211,12 +203,23 @@ class _MihPatientSearchState extends State { _mihPatientSearchResults = MIHApiCalls.fetchPatients("abc"); } + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + _searchFocusNode.dispose(); + _mihPatientSearchController.dispose(); + _focusNode.dispose(); + } + @override Widget build(BuildContext context) { + final Size size = MediaQuery.sizeOf(context); + final double width = size.width; return MihPackageToolBody( borderOn: false, innerHorizontalPadding: 10, - bodyItem: getPatientSearch(), + bodyItem: getPatientSearch(width), ); } } diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/my_patient_list.dart b/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/my_patient_list.dart index 0b649b4f..75999d9d 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/my_patient_list.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/my_patient_list.dart @@ -1,8 +1,8 @@ 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_search_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_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.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'; @@ -34,12 +34,13 @@ class MyPatientList extends StatefulWidget { class _MyPatientListState extends State { late Future> _myPatientList; TextEditingController _myPatientSearchController = TextEditingController(); + final FocusNode _searchFocusNode = FocusNode(); String _myPatientIdSearchString = ""; String baseUrl = AppEnviroment.baseApiUrl; final FocusNode _focusNode = FocusNode(); - Widget myPatientListTool() { + Widget myPatientListTool(double width) { return MihSingleChildScroll( child: KeyboardListener( focusNode: _focusNode, @@ -55,62 +56,31 @@ class _MyPatientListState extends State { } }, child: Column(mainAxisSize: MainAxisSize.max, children: [ - // Row( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // const Text( - // "My Patient List", - // style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold), - // ), - // IconButton( - // iconSize: 20, - // icon: const Icon( - // Icons.refresh, - // ), - // onPressed: () { - // getMyPatientList(); - // }, - // ), - // ], - // ), - // Divider( - // color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), - // //spacer - // const SizedBox(height: 10), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - flex: 1, - child: MIHSearchField( - controller: _myPatientSearchController, - hintText: "Patient ID Search", - required: false, - editable: true, - onTap: () { - setState(() { - _myPatientIdSearchString = - _myPatientSearchController.text; - _myPatientList = - MIHApiCalls.getPatientAccessListOfBusiness( - widget.business!.business_id); - }); - }, - ), - ), - IconButton( - onPressed: () { - setState(() { - _myPatientSearchController.clear(); - _myPatientIdSearchString = ""; - }); - getMyPatientList(); - }, - icon: const Icon( - Icons.filter_alt_off, - size: 25, - )) - ], + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: _myPatientSearchController, + hintText: "Search by ID", + prefixIcon: Icons.search, + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { + setState(() { + _myPatientIdSearchString = _myPatientSearchController.text; + _myPatientList = MIHApiCalls.getPatientAccessListOfBusiness( + widget.business!.business_id); + }); + }, + onClearIconTap: () { + setState(() { + _myPatientSearchController.clear(); + _myPatientIdSearchString = ""; + }); + getMyPatientList(); + }, + searchFocusNode: _searchFocusNode, + ), ), //spacer const SizedBox(height: 10), @@ -199,12 +169,23 @@ class _MyPatientListState extends State { widget.business!.business_id); } + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + _myPatientSearchController.dispose(); + _searchFocusNode.dispose(); + _focusNode.dispose(); + } + @override Widget build(BuildContext context) { + final Size size = MediaQuery.sizeOf(context); + final double width = size.width; return MihPackageToolBody( borderOn: false, innerHorizontalPadding: 10, - bodyItem: myPatientListTool(), + bodyItem: myPatientListTool(width), ); } } 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 0344b7cb..a13a7de1 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,12 +1,13 @@ +import 'package:flutter/services.dart'; import 'package:mzansi_innovation_hub/main.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_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_search_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_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_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'; @@ -64,6 +65,8 @@ class _ClaimStatementWindowState extends State { final ValueNotifier serviceDesc = ValueNotifier(""); final ValueNotifier medAid = ValueNotifier(""); List icd10codeList = []; + final FocusNode _searchFocusNode = FocusNode(); + final FocusNode _focusNode = FocusNode(); void icd10SearchWindow(List codeList) { showDialog( @@ -186,18 +189,35 @@ class _ClaimStatementWindowState extends State { }, ), //const SizedBox(height: 10), - MIHSearchField( - controller: _icd10CodeController, - hintText: "ICD-10 Code & Description", - required: true, - editable: true, - onTap: () { - //api - MIHIcd10CodeApis.getIcd10Codes(_icd10CodeController.text, context) - .then((result) { - icd10SearchWindow(result); - }); + KeyboardListener( + focusNode: _focusNode, + autofocus: true, + onKeyEvent: (event) async { + if (event is KeyDownEvent && + event.logicalKey == LogicalKeyboardKey.enter) { + MIHIcd10CodeApis.getIcd10Codes(_icd10CodeController.text, context) + .then((result) { + icd10SearchWindow(result); + }); + } }, + child: 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( @@ -365,6 +385,7 @@ class _ClaimStatementWindowState extends State { _proceedureAdditionalInfoController.dispose(); _icd10CodeController.dispose(); _preauthNoController.dispose(); + _searchFocusNode.dispose(); super.dispose(); } diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart index c5275651..5f55396d 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart @@ -2,9 +2,9 @@ import 'dart:convert'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/medicine_search.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_search_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; @@ -54,6 +54,7 @@ class PrescripInput extends StatefulWidget { class _PrescripInputState extends State { final FocusNode _focusNode = FocusNode(); + final FocusNode _searchFocusNode = FocusNode(); List perscriptionObjOutput = []; late double width; late double height; @@ -361,28 +362,23 @@ class _PrescripInputState extends State { getMedsPopUp(widget.medicineController); } }, - child: MIHSearchField( + child: MihSearchBar( controller: widget.medicineController, - hintText: "Medicine", - required: true, - editable: true, - onTap: () { + hintText: "Search Medicine", + prefixIcon: Icons.search, + fillColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + hintColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPrefixIconTap: () { getMedsPopUp(widget.medicineController); }, + onClearIconTap: () { + widget.medicineController.clear(); + }, + searchFocusNode: _searchFocusNode, ), ), const SizedBox(height: 10.0), - // SizedBox( - // width: 300, - // child: MIHDropdownField( - // controller: widget.quantityController, - // hintText: "Quantity", - // dropdownOptions: numberOptions, - // required: true, - // editable: true, - // ), - // ), - // const SizedBox(height: 10.0), + MIHDropdownField( controller: widget.dosageController, hintText: "Dosage", @@ -544,6 +540,7 @@ class _PrescripInputState extends State { @override void dispose() { _focusNode.dispose(); + _searchFocusNode.dispose(); super.dispose(); } diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart index c0719953..544bbe2c 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart @@ -423,8 +423,8 @@ class _PatientDocumentsState extends State { ); } else { return Positioned( - right: 0, - bottom: 0, + right: 10, + bottom: 10, child: MihFloatingMenu( icon: Icons.add, animatedIcon: AnimatedIcons.menu_close,