From 5b5cc16b90d6aa7696f79e7d55efedd68470d2a5 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 18 Oct 2022 13:41:31 +0300 Subject: [PATCH] Advanced Search implemented --- assets/langs/ar-SA.json | 13 +- assets/langs/en-US.json | 13 +- lib/api/offers_and_discounts_api_client.dart | 4 +- lib/api/worklist/worklist_api_client.dart | 23 +- lib/extensions/string_extensions.dart | 4 +- lib/generated/codegen_loader.g.dart | 26 +- lib/generated/locale_keys.g.dart | 11 + lib/ui/landing/dashboard_screen.dart | 2 +- lib/ui/work_list/work_list_screen.dart | 321 ++++++++++++++++++- 9 files changed, 394 insertions(+), 23 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index a21411d..161bde6 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -454,5 +454,16 @@ "reset_locale": "Reset Language", "chat": "دردشة", "mychats": "دردشاتي", - "createNewChat": "Create New Chat" + "createNewChat": "Create New Chat", + "advancedSearch": "بحث متقدم", + "openNot": "التبليغات المفتوحة", + "fyi": "تبليغات للعلم", + "toDo": "تبليغات الأعمال", + "all": "كل التبليغات", + "meNot": "تبليغات صادرة مني", + "view": "عرض", + "fromUserName": "من", + "sentDate": "تاريخ الإرسال", + "itemTypeDisplayName": "اسم العرض", + "none": "بدون" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index b5a607c..b88b14c 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -454,5 +454,16 @@ "reset_locale": "Reset Language", "chat": "Chat", "mychats": "My Chats", - "createNewChat": "Create New Chat" + "createNewChat": "Create New Chat", + "advancedSearch": "Advanced Search", + "openNot": "Open Notifications", + "fyi": "FYI Notifications", + "toDo": "To Do Notifications", + "all": "All Notifications", + "meNot": "Notifications from Me", + "view": "View", + "fromUserName": "From User Name", + "sentDate": "Sent Date", + "itemTypeDisplayName": "Item Type Display Name", + "none": "None" } \ No newline at end of file diff --git a/lib/api/offers_and_discounts_api_client.dart b/lib/api/offers_and_discounts_api_client.dart index b5aa9e6..6189612 100644 --- a/lib/api/offers_and_discounts_api_client.dart +++ b/lib/api/offers_and_discounts_api_client.dart @@ -57,9 +57,11 @@ class OffersAndDiscountsApiClient { var bodyData = json.decode(body['result']['data']); - bodyData.forEach((v) { + if(bodyData != null) { + bodyData.forEach((v) { getSaleCategoriesList.add(OffersListModel.fromJson(v)); }); + } return getSaleCategoriesList; }, url, diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index 91c0db0..8c5aed2 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -28,7 +28,6 @@ import 'package:mohem_flutter_app/models/worklist/hr/get_basic_det_ntf_body_list import 'package:mohem_flutter_app/models/worklist/hr/get_contact_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_phones_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; -import 'package:mohem_flutter_app/models/worklist/update_user_type_list.dart'; import 'package:mohem_flutter_app/models/worklist_response_model.dart'; class WorkListApiClient { @@ -38,13 +37,18 @@ class WorkListApiClient { factory WorkListApiClient() => _instance; - Future?> getWorkList(int pPageNum, String pItemType) async { + Future?> getWorkList(int pPageNum, String pItemType, String pNotificationType, + {String pSearchUser = "", String pSearchItemType = "", String pSentDate = "", String pSearchSubject = ""}) async { String url = "${ApiConsts.erpRest}GET_WORKLIST"; Map postParams = { - "P_NOTIFICATION_TYPE": "1", + "P_NOTIFICATION_TYPE": pNotificationType, "P_PAGE_NUM": pPageNum, - "P_PAGE_LIMIT": 50, + "P_PAGE_LIMIT": 25, "P_ITEM_TYPE": pItemType, + "P_SEARCH_FROM_USER": pSearchUser, + "P_SEARCH_ITEM_TYPE_DSP_NAME": pSearchItemType, + "P_SEARCH_SENT_DATE": pSentDate, + "P_SEARCH_SUBJECT": pSearchSubject }; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { @@ -481,12 +485,9 @@ class WorkListApiClient { }, url, postParams); } - Future> getUserItemTypes() async { String url = "${ApiConsts.erpRest}GET_USER_ITEM_TYPES"; - Map postParams = { - - }; + Map postParams = {}; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { GenericResponseModel responseData = GenericResponseModel.fromJson(json); @@ -496,15 +497,11 @@ class WorkListApiClient { Future updateUserItemTypes(List> itemList) async { String url = "${ApiConsts.erpRest}UPDATE_USER_ITEM_TYPES"; - Map postParams = { - "UpdateItemTypeList": itemList - }; + Map postParams = {"UpdateItemTypeList": itemList}; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { GenericResponseModel responseData = GenericResponseModel.fromJson(json); return responseData.updateUserItemTypesList; }, url, postParams); } - - } diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index a9075c7..2462f57 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -65,10 +65,10 @@ extension EmailValidator on String { style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.52, decoration: isUnderLine ? TextDecoration.underline : null), ); - Widget toText14({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text( + Widget toText14({Color? color, bool isUnderLine = false, bool isBold = false, FontWeight? weight, int? maxlines}) => Text( this, maxLines: maxlines, - style: TextStyle(color: color ?? MyColors.darkTextColor, fontSize: 14, letterSpacing: -0.48, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.w600)), + style: TextStyle(color: color ?? MyColors.darkTextColor, fontSize: 14, letterSpacing: -0.48, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.w600), decoration: isUnderLine ? TextDecoration.underline : null), ); Widget toText16({Color? color, bool isUnderLine = false, bool isBold = false, int? maxlines}) => Text( diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 37e5d4e..42dc55e 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -470,7 +470,18 @@ class CodegenLoader extends AssetLoader{ "reset_locale": "Reset Language", "chat": "دردشة", "mychats": "دردشاتي", - "createNewChat": "Create New Chat" + "createNewChat": "Create New Chat", + "advancedSearch": "بحث متقدم", + "openNot": "التبليغات المفتوحة", + "fyi": "تبليغات للعلم", + "toDo": "تبليغات الأعمال", + "all": "كل التبليغات", + "meNot": "تبليغات صادرة مني", + "view": "عرض", + "fromUserName": "من", + "sentDate": "تاريخ الإرسال", + "itemTypeDisplayName": "اسم العرض", + "none": "بدون" }; static const Map en_US = { "mohemm": "Mohemm", @@ -928,7 +939,18 @@ static const Map en_US = { "reset_locale": "Reset Language", "chat": "Chat", "mychats": "My Chats", - "createNewChat": "Create New Chat" + "createNewChat": "Create New Chat", + "advancedSearch": "Advanced Search", + "openNot": "Open Notifications", + "fyi": "FYI Notifications", + "toDo": "To Do Notifications", + "all": "All Notifications", + "meNot": "Notifications from Me", + "view": "View", + "fromUserName": "From User Name", + "sentDate": "Sent Date", + "itemTypeDisplayName": "Item Type Display Name", + "none": "None" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 85b677d..b17f5ba 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -441,5 +441,16 @@ abstract class LocaleKeys { static const chat = 'chat'; static const mychats = 'mychats'; static const createNewChat = 'createNewChat'; + static const advancedSearch = 'advancedSearch'; + static const openNot = 'openNot'; + static const fyi = 'fyi'; + static const toDo = 'toDo'; + static const all = 'all'; + static const meNot = 'meNot'; + static const view = 'view'; + static const fromUserName = 'fromUserName'; + static const sentDate = 'sentDate'; + static const itemTypeDisplayName = 'itemTypeDisplayName'; + static const none = 'none'; } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 026d17e..0e21937 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -414,7 +414,7 @@ class _DashboardScreenState extends State { "assets/icons/item_for_sale.svg", color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color, ).paddingAll(4), - label: LocaleKeys.chat.tr(), + label: LocaleKeys.itemsForSale.tr(), ), BottomNavigationBarItem( icon: SvgPicture.asset( diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index 1eaac3e..de0815c 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -1,4 +1,7 @@ +import 'dart:io'; + import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:mohem_flutter_app/api/worklist/worklist_api_client.dart'; @@ -18,6 +21,9 @@ import 'package:mohem_flutter_app/models/worklist_item_type_model.dart'; import 'package:mohem_flutter_app/models/worklist_response_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; import 'package:provider/provider.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; @@ -87,12 +93,36 @@ class _WorkListScreenState extends State { final RefreshController _refreshController = RefreshController(initialRefresh: false); + final Map advancedSearchViews = {}; + final Map advancedSearchSearchBy = {}; + final Map advancedSearchItemType = {}; + + int selectedViewID = 1; + String? selectedViewName; + + int selectedSearchByID = 0; + String? selectedSearchByName; + + String selectedItemTypeID = ""; + String? selectedItemTypeName; + + String searchByInput = ""; + String searchByDate = ""; + + DateTime selectedDate = DateTime.now(); + final ScrollController _controller = ScrollController(); + @override void initState() { super.initState(); providerData = Provider.of(context, listen: false); calculateCounter(); getWorkList(); + setupAdvancedSearchParams(); + } + + void setupAdvancedSearchParams() { + advancedSearchViews.addAll({1: LocaleKeys.openNot.tr(), 2: LocaleKeys.fyi.tr(), 3: LocaleKeys.toDo.tr(), 4: LocaleKeys.all.tr(), 5: LocaleKeys.meNot.tr()}); } void calculateCounter() { @@ -132,7 +162,7 @@ class _WorkListScreenState extends State { } } else { itgRequestTypeIndex = null; - workList = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex].key); + workList = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex].key, selectedViewID.toString()); AppState().setWorkList = workList; } if (showLoading) Utils.hideLoading(context); @@ -183,6 +213,7 @@ class _WorkListScreenState extends State { SizedBox( height: 40, child: ListView.separated( + controller: _controller, itemBuilder: (context, index) { return Container( padding: const EdgeInsets.only(left: 21, right: 21, top: 8, bottom: 8), @@ -213,7 +244,15 @@ class _WorkListScreenState extends State { padding: const EdgeInsets.only(left: 21, right: 21), ), ).paddingOnly(top: 21, bottom: 21), - workListItemTypes[workListItemIndex].fullName.toSectionHeading().paddingOnly(left: 21, right: 21), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + workListItemTypes[workListItemIndex].fullName.toSectionHeading().paddingOnly(left: 21, right: 21), + LocaleKeys.advancedSearch.tr().toText14(isUnderLine: true).onPress(() { + openBottomSheet(context); + }).paddingOnly(left: 21, right: 21) + ], + ), SmartRefresher( enablePullDown: true, enablePullUp: false, @@ -364,6 +403,147 @@ class _WorkListScreenState extends State { ); } + void openBottomSheet(BuildContext context) { + showMyBottomSheet( + context, + child: Padding( + padding: const EdgeInsets.all(21.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocaleKeys.advancedSearch.tr().toText18(), + IconButton( + icon: const Icon(Icons.close, color: MyColors.darkIconColor), + onPressed: () => Navigator.pop(context), + ), + ], + ), + 12.height, + PopupMenuButton( + child: DynamicTextFieldWidget( + LocaleKeys.view.tr(), + selectedViewName != null ? selectedViewName! : LocaleKeys.view.tr(), + isEnable: false, + isPopup: true, + isInputTypeNum: true, + isReadOnly: false, + ), + itemBuilder: (_) => >[ + PopupMenuItem(value: 1, child: Text(LocaleKeys.openNot.tr())), + PopupMenuItem(value: 2, child: Text(LocaleKeys.fyi.tr())), + PopupMenuItem(value: 3, child: Text(LocaleKeys.toDo.tr())), + PopupMenuItem(value: 4, child: Text(LocaleKeys.all.tr())), + PopupMenuItem(value: 5, child: Text(LocaleKeys.meNot.tr())), + ], + onSelected: (int popupIndex) { + selectedViewID = popupIndex; + selectedViewName = getSelectedViewName(popupIndex); + setState(() {}); + }, + ), + 12.height, + PopupMenuButton( + child: DynamicTextFieldWidget( + LocaleKeys.searchBy.tr(), + selectedSearchByName != null ? selectedSearchByName! : LocaleKeys.searchBy.tr(), + isEnable: false, + isPopup: true, + isInputTypeNum: true, + isReadOnly: false, + ), + itemBuilder: (_) => >[ + PopupMenuItem(value: 1, child: Text(LocaleKeys.fromUserName.tr())), + PopupMenuItem(value: 2, child: Text(LocaleKeys.subject.tr())), + PopupMenuItem(value: 3, child: Text(LocaleKeys.sentDate.tr())), + PopupMenuItem(value: 4, child: Text(LocaleKeys.itemTypeDisplayName.tr())), + PopupMenuItem(value: 5, child: Text(LocaleKeys.none.tr())), + ], + onSelected: (int popupIndex) { + selectedSearchByID = popupIndex; + selectedSearchByName = getSelectedSearchByName(popupIndex); + setState(() {}); + }, + ), + 12.height, + if (selectedSearchByID == 1 || selectedSearchByID == 2 || selectedSearchByID == 4) + DynamicTextFieldWidget( + LocaleKeys.searchBy.tr(), + LocaleKeys.searchBy.tr(), + isEnable: true, + isPopup: false, + lines: 1, + isInputTypeNum: false, + isReadOnly: false, + onChange: (String value) { + debugPrint(value); + searchByInput = value; + }, + ), + if (selectedSearchByID == 3) + DynamicTextFieldWidget( + LocaleKeys.searchBy.tr(), + LocaleKeys.sentDate.tr(), + suffixIconData: Icons.calendar_today, + isEnable: false, + onTap: () async { + selectedDate = await _selectDate(context, DateTime.now()); + searchByDate = selectedDate.day.toString() + "-" + getMonth(selectedDate.month) + "-" + selectedDate.year.toString(); + setState(() {}); + }, + ), + 12.height, + PopupMenuButton( + child: DynamicTextFieldWidget( + LocaleKeys.itemType.tr(), + selectedItemTypeName != null ? selectedItemTypeName! : LocaleKeys.itemType.tr(), + isEnable: false, + isPopup: true, + isInputTypeNum: true, + isReadOnly: false, + ), + itemBuilder: (_) => >[ + const PopupMenuItem(value: "HRSSA", child: Text("HR")), + const PopupMenuItem(value: "POAPPRV", child: Text("PO")), + const PopupMenuItem(value: "REQAPPRV", child: Text("PR")), + const PopupMenuItem(value: "INVMOA", child: Text("MR")), + const PopupMenuItem(value: "INVITEM", child: Text("IC")), + const PopupMenuItem(value: "STAMP", child: Text("STAMP")), + ], + onSelected: (String popupIndex) { + selectedItemTypeID = popupIndex; + selectedItemTypeName = getSelectedItemType(popupIndex); + setState(() {}); + }, + ), + 20.height, + DefaultButton(LocaleKeys.search.tr(), () async { + Navigator.pop(context); + itgRequestTypeIndex = null; + int index = -1; + for (int i = 0; i < workListItemTypes.length; i++) { + if (workListItemTypes[i].key == selectedItemTypeID) { + index = i; + break; + } + } + Utils.showLoading(context); + workList = await WorkListApiClient().getWorkList(pageNumber, selectedItemTypeID, selectedViewID.toString(), + pSearchUser: searchByInput, pSearchSubject: searchByInput, pSentDate: searchByDate, pSearchItemType: searchByInput); + workListItemIndex = index; + AppState().setWorkList = workList; + _animateToIndex(index, 50.0); + Utils.hideLoading(context); + setState(() {}); + }) + ], + ), + ), + ); + } + Widget rowItem(WorkListItemTypeModelData data, WorkListResponseModel workData, int index) { return InkWell( onTap: () async { @@ -442,4 +622,141 @@ class _WorkListScreenState extends State { ), ); } + + void _animateToIndex(int index, double width) { + _controller.animateTo( + index * width, + duration: const Duration(seconds: 1), + curve: Curves.fastOutSlowIn, + ); + } + + String getSelectedViewName(int index) { + String returnVal = ""; + switch (index) { + case 1: + returnVal = LocaleKeys.openNot.tr(); + break; + case 2: + returnVal = LocaleKeys.fyi.tr(); + break; + case 3: + returnVal = LocaleKeys.toDo.tr(); + break; + case 4: + returnVal = LocaleKeys.all.tr(); + break; + case 5: + returnVal = LocaleKeys.meNot.tr(); + break; + } + return returnVal; + } + + String getSelectedSearchByName(int index) { + String returnVal = ""; + switch (index) { + case 1: + returnVal = LocaleKeys.fromUserName.tr(); + break; + case 2: + returnVal = LocaleKeys.subject.tr(); + break; + case 3: + returnVal = LocaleKeys.sentDate.tr(); + break; + case 4: + returnVal = LocaleKeys.itemType.tr(); + break; + case 5: + returnVal = LocaleKeys.none.tr(); + break; + } + return returnVal; + } + + String getSelectedItemType(String index) { + String returnVal = ""; + switch (index) { + case "HRSSA": + returnVal = "HR"; + break; + case "POAPPRV": + returnVal = "PO"; + break; + case "REQAPPRV": + returnVal = "PR"; + break; + case "INVMOA": + returnVal = "MR"; + break; + case "INVITEM": + returnVal = "IC"; + break; + case "STAMP": + returnVal = "STAMP"; + break; + } + return returnVal; + } + + Future _selectDate(BuildContext context, DateTime selectedDate) async { + DateTime time = selectedDate; + if (!Platform.isIOS) { + await showCupertinoModalPopup( + context: context, + builder: (cxt) => Container( + height: 250, + color: Colors.white, + child: CupertinoDatePicker( + backgroundColor: Colors.white, + mode: CupertinoDatePickerMode.date, + onDateTimeChanged: (value) { + if (value != null && value != selectedDate) { + time = value; + } + }, + initialDateTime: selectedDate, + ), + ), + ); + } else { + DateTime? picked = await showDatePicker(context: context, initialDate: selectedDate, initialEntryMode: DatePickerEntryMode.calendarOnly, firstDate: DateTime(2015, 8), lastDate: DateTime(2101)); + if (picked != null && picked != selectedDate) { + time = picked; + } + } + return time; + } + + String getMonth(int month) { + switch (month) { + case 1: + return "Jan"; + case 2: + return "Feb"; + case 3: + return "Mar"; + case 4: + return "Apr"; + case 5: + return "May"; + case 6: + return "June"; + case 7: + return "July"; + case 8: + return "Aug"; + case 9: + return "Sep"; + case 10: + return "Oct"; + case 11: + return "Nov"; + case 12: + return "Dec"; + default: + return ""; + } + } }