From 7b6783a5da1710aa73b3eb4cebefc2b9450a19f3 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 <50428976+WaseemAbbasi22@users.noreply.github.com> Date: Tue, 15 Sep 2026 11:56:00 +0300 Subject: [PATCH 1/4] pagination added --- .../asset_tracking/asset_tracking_page.dart | 224 ++++++++++-------- .../asset_tracking_provider.dart | 35 ++- 2 files changed, 149 insertions(+), 110 deletions(-) diff --git a/lib/modules/asset_tracking/asset_tracking_page.dart b/lib/modules/asset_tracking/asset_tracking_page.dart index ce2213b7..fa1ef7be 100644 --- a/lib/modules/asset_tracking/asset_tracking_page.dart +++ b/lib/modules/asset_tracking/asset_tracking_page.dart @@ -1,23 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:flutter_map/flutter_map.dart'; -import 'package:flutter_map_geojson2/flutter_map_geojson2.dart'; - -import 'package:latlong2/latlong.dart'; -import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; -import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/asset_tracking/asset_tracking_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; -import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; -import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; -import 'package:test_sa/views/widgets/requests/request_status.dart'; - import 'asset_tracking_item_view.dart'; import 'map_tracking_page.dart'; @@ -46,10 +36,16 @@ class _AssetTrackingPageState extends State with SingleTicker _animationController.forward(); WidgetsBinding.instance.addPostFrameCallback((_) { assetTrackingProvider.reset(); - assetTrackingProvider.getAssetsFromPenguin(); + getAssetsFromPenguin(); }); } + Future getAssetsFromPenguin({bool loadMore = false}) async { + await assetTrackingProvider.getAssetsFromPenguin( + loadMore: loadMore, + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -118,48 +114,60 @@ class _AssetTrackingPageState extends State with SingleTicker return Consumer(builder: (context, provider, _) { return (provider.assetsList.isEmpty && !provider.isLoading) ? NoDataFound(message: context.translation.noDataFound).center - : ListView.separated( - key: const ValueKey('asset-list_view'), - padding: const EdgeInsets.all(16), - itemCount: provider.isLoading ? 6 : provider.assetsList.length, - separatorBuilder: (listContext, itemIndex) => 12.height, - itemBuilder: (listContext, itemIndex) { - if (provider.isLoading) return const SizedBox().toAssetListShimmer(listContext, provider.isLoading); - - // Calculate staggered animation delay - final delay = itemIndex * 0.08; - final animation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.7), - (delay + 0.4).clamp(0.0, 1.0), - curve: Curves.easeOut, + : NotificationListener( + onNotification: (scrollInfo) { + if (!provider.isNextPageLoading && provider.nextPage && scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) { + getAssetsFromPenguin(loadMore: true); + } + return false; + }, + child: ListView.separated( + key: const ValueKey('asset-list_view'), + padding: const EdgeInsets.all(16), + itemCount: provider.isLoading ? 6 : provider.assetsList.length + (provider.isNextPageLoading ? 1 : 0), + separatorBuilder: (listContext, itemIndex) => 12.height, + itemBuilder: (listContext, itemIndex) { + if (provider.isLoading) return const SizedBox().toAssetListShimmer(listContext, provider.isLoading); + if (itemIndex >= provider.assetsList.length) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Center(child: CircularProgressIndicator()), + ); + } + final delay = itemIndex * 0.08; + final animation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.7), + (delay + 0.4).clamp(0.0, 1.0), + curve: Curves.easeOut, + ), ), - ), - ); - - final slideAnimation = Tween( - begin: const Offset(0.0, 0.15), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.7), - (delay + 0.4).clamp(0.0, 1.0), - curve: Curves.easeOutCubic, + ); + + final slideAnimation = Tween( + begin: const Offset(0.0, 0.15), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.7), + (delay + 0.4).clamp(0.0, 1.0), + curve: Curves.easeOutCubic, + ), ), - ), - ); - - return FadeTransition( - opacity: animation, - child: SlideTransition(position: slideAnimation, child: AssetTrackingListItemView(provider.assetsList[itemIndex])).onPress(() { - Navigator.push(context, MaterialPageRoute(builder: (context) => MapTrackingPage(assetTrackingData: provider.assetsList[itemIndex]))); - }), - ); - }, + ); + + return FadeTransition( + opacity: animation, + child: SlideTransition(position: slideAnimation, child: AssetTrackingListItemView(provider.assetsList[itemIndex])).onPress(() { + Navigator.push(context, MaterialPageRoute(builder: (context) => MapTrackingPage(assetTrackingData: provider.assetsList[itemIndex]))); + }), + ); + }, + ), ); }); } @@ -173,56 +181,78 @@ class _AssetTrackingPageState extends State with SingleTicker // // padding: const EdgeInsets.all(16), - GridView.builder( - key: const ValueKey('asset-grid_view'), - padding: const EdgeInsets.all(16), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - childAspectRatio: .8, - crossAxisSpacing: 12, - mainAxisSpacing: 12, - ), + NotificationListener( + onNotification: (scrollInfo) { + if (!provider.isLoading && + !provider.isNextPageLoading && + provider.nextPage && + scrollInfo.metrics.pixels >= (scrollInfo.metrics.maxScrollExtent - 200)) { + getAssetsFromPenguin(loadMore: true); + } + return false; + }, + child: Column( + children: [ + Expanded( + child: GridView.builder( + key: const ValueKey('asset-grid_view'), + padding: const EdgeInsets.all(16), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: .8, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + + itemCount: provider.isLoading ? 6 : provider.assetsList.length, + // separatorBuilder: (listContext, itemIndex) => 12.height, + + itemBuilder: (listContext, itemIndex) { + if (provider.isLoading) return const SizedBox().toAssetListShimmer(listContext, provider.isLoading); - itemCount: provider.isLoading ? 6 : provider.assetsList.length, - // separatorBuilder: (listContext, itemIndex) => 12.height, - - itemBuilder: (listContext, itemIndex) { - if (provider.isLoading) return const SizedBox().toAssetListShimmer(listContext, provider.isLoading); - - // Calculate staggered animation delay - final delay = itemIndex * 0.08; - final animation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.7), - (delay + 0.4).clamp(0.0, 1.0), - curve: Curves.easeOut, + // Calculate staggered animation delay + final delay = itemIndex * 0.08; + final animation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.7), + (delay + 0.4).clamp(0.0, 1.0), + curve: Curves.easeOut, + ), + ), + ); + + final slideAnimation = Tween( + begin: const Offset(0.0, 0.15), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.7), + (delay + 0.4).clamp(0.0, 1.0), + curve: Curves.easeOutCubic, + ), + ), + ); + + return FadeTransition( + opacity: animation, + child: SlideTransition(position: slideAnimation, child: AssetTrackingListItemView(provider.assetsList[itemIndex])).onPress(() { + Navigator.push(context, MaterialPageRoute(builder: (context) => MapTrackingPage(assetTrackingData: provider.assetsList[itemIndex]))); + }), + ); + }, ), ), - ); - - final slideAnimation = Tween( - begin: const Offset(0.0, 0.15), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.7), - (delay + 0.4).clamp(0.0, 1.0), - curve: Curves.easeOutCubic, + if (provider.isNextPageLoading) + const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Center(child: CircularProgressIndicator()), ), - ), - ); - - return FadeTransition( - opacity: animation, - child: SlideTransition(position: slideAnimation, child: AssetTrackingListItemView(provider.assetsList[itemIndex])).onPress(() { - Navigator.push(context, MaterialPageRoute(builder: (context) => MapTrackingPage(assetTrackingData: provider.assetsList[itemIndex]))); - }), - ); - }, + ], + ), ); }); } diff --git a/lib/modules/asset_tracking/asset_tracking_provider.dart b/lib/modules/asset_tracking/asset_tracking_provider.dart index fe99bd86..ae21666c 100644 --- a/lib/modules/asset_tracking/asset_tracking_provider.dart +++ b/lib/modules/asset_tracking/asset_tracking_provider.dart @@ -13,7 +13,7 @@ class AssetTrackingProvider extends ChangeNotifier { bool isNextPageLoading = false; final pageItemNumber = 12; int pageNo = 1; - + bool nextPage = false; List assetsList = []; List assetsOnTheFloorList = []; @@ -30,6 +30,9 @@ class AssetTrackingProvider extends ChangeNotifier { reset() { isLoading = false; + isNextPageLoading = false; + pageNo = 1; + nextPage = false; selectedFloor = null; selectedBuilding = null; selectedSite = null; @@ -57,26 +60,31 @@ class AssetTrackingProvider extends ChangeNotifier { final response = await ApiManager.instance.post(URLs.getAssetsFromPenguin, body: payload); if (response.statusCode >= 200 && response.statusCode < 300) { final Map jsonData = json.decode(response.body); - List list = jsonData["data"]; - assetsList.addAll(list.map((item) => AssetTrackingModel.fromJson(item)).toList()); - if (jsonData["totalRows"] <= assetsList.length) { - // nextPage = true; - } - // if (loadMore) { - // assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []); - // assetInventoryResponse?.totalRows = newResponse.totalRows; - // } else { - // assetInventoryResponse = newResponse; + List list = jsonData["data"] ?? []; + List responseAssetList = list.map((item) => AssetTrackingModel.fromJson(item)).toList(); + + // assetsList.addAll(list.map((item) => AssetTrackingModel.fromJson(item)).toList()); + // if (jsonData["totalRows"] <= assetsList.length) { + // nextPage = true; // } - // nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0); + if (loadMore) { + assetsList.addAll(responseAssetList); + // assetInventoryResponse?.totalRows = newResponse.totalRows; + } else { + assetsList = responseAssetList; + // assetInventoryResponse = newResponse; + } + final int totalRows = (jsonData["totalRows"] as int?) ?? assetsList.length; + nextPage = (assetsList.length) < totalRows; } else { - // nextPage = false; + if (loadMore) pageNo -= 1; } isLoading = false; isNextPageLoading = false; notifyListeners(); return response.statusCode; } catch (error) { + if (loadMore) pageNo -= 1; isLoading = false; isNextPageLoading = false; // stateCode = -1; @@ -86,6 +94,7 @@ class AssetTrackingProvider extends ChangeNotifier { } } + Future getAssetsFromPenguinByFloor() async { try { assetsOnTheFloorList.clear(); From 0dc3eee22bdf60559f1fe28211cc9a2ddb2d5bfb Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 <50428976+WaseemAbbasi22@users.noreply.github.com> Date: Tue, 15 Sep 2026 14:34:45 +0300 Subject: [PATCH 2/4] pagination added need to review ui --- .../asset_tracking_item_view.dart | 17 +++++++++++--- .../asset_tracking/asset_tracking_page.dart | 23 +++++++------------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/lib/modules/asset_tracking/asset_tracking_item_view.dart b/lib/modules/asset_tracking/asset_tracking_item_view.dart index 4b24b73a..0b726413 100644 --- a/lib/modules/asset_tracking/asset_tracking_item_view.dart +++ b/lib/modules/asset_tracking/asset_tracking_item_view.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; @@ -11,8 +12,9 @@ import 'models/asset_tracking_model.dart'; class AssetTrackingListItemView extends StatelessWidget { final AssetTrackingModel asset; + bool isGridView; - AssetTrackingListItemView(this.asset, {Key? key}) : super(key: key); + AssetTrackingListItemView(this.asset, this.isGridView, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -36,9 +38,18 @@ class AssetTrackingListItemView extends StatelessWidget { label: "Last seen", value: asset.location?.lastSeen?.toServiceRequestDetailsFormat, showEmptyValue: true, - showArrow: true, - arrowMsg: "View on map", + showArrow: isGridView ? false : true, + arrowMsg: isGridView ? "" : "View on map", ), + if (isGridView) ...[ + 4.height, + InfoTextWidget( + label: "View on map", + value: '', + showEmptyValue: true, + showArrow: true, + ), + ], ], ).toShadowContainer(context); } diff --git a/lib/modules/asset_tracking/asset_tracking_page.dart b/lib/modules/asset_tracking/asset_tracking_page.dart index fa1ef7be..a4c1a28e 100644 --- a/lib/modules/asset_tracking/asset_tracking_page.dart +++ b/lib/modules/asset_tracking/asset_tracking_page.dart @@ -7,6 +7,7 @@ import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/asset_tracking/asset_tracking_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'asset_tracking_item_view.dart'; import 'map_tracking_page.dart'; @@ -131,7 +132,7 @@ class _AssetTrackingPageState extends State with SingleTicker if (itemIndex >= provider.assetsList.length) { return const Padding( padding: EdgeInsets.symmetric(vertical: 16), - child: Center(child: CircularProgressIndicator()), + child: ALoading(), ); } final delay = itemIndex * 0.08; @@ -162,7 +163,7 @@ class _AssetTrackingPageState extends State with SingleTicker return FadeTransition( opacity: animation, - child: SlideTransition(position: slideAnimation, child: AssetTrackingListItemView(provider.assetsList[itemIndex])).onPress(() { + child: SlideTransition(position: slideAnimation, child: AssetTrackingListItemView(provider.assetsList[itemIndex], false)).onPress(() { Navigator.push(context, MaterialPageRoute(builder: (context) => MapTrackingPage(assetTrackingData: provider.assetsList[itemIndex]))); }), ); @@ -176,17 +177,9 @@ class _AssetTrackingPageState extends State with SingleTicker return Consumer(builder: (context, provider, _) { return (provider.assetsList.isEmpty && !provider.isLoading) ? NoDataFound(message: context.translation.noDataFound).center - : - // ListView.separated( - // - // padding: const EdgeInsets.all(16), - - NotificationListener( + : NotificationListener( onNotification: (scrollInfo) { - if (!provider.isLoading && - !provider.isNextPageLoading && - provider.nextPage && - scrollInfo.metrics.pixels >= (scrollInfo.metrics.maxScrollExtent - 200)) { + if (!provider.isLoading && !provider.isNextPageLoading && provider.nextPage && scrollInfo.metrics.pixels >= (scrollInfo.metrics.maxScrollExtent - 200)) { getAssetsFromPenguin(loadMore: true); } return false; @@ -199,7 +192,7 @@ class _AssetTrackingPageState extends State with SingleTicker padding: const EdgeInsets.all(16), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, - childAspectRatio: .8, + childAspectRatio: 1.2, // need to fix this it's not flexiable with content.. crossAxisSpacing: 12, mainAxisSpacing: 12, ), @@ -239,7 +232,7 @@ class _AssetTrackingPageState extends State with SingleTicker return FadeTransition( opacity: animation, - child: SlideTransition(position: slideAnimation, child: AssetTrackingListItemView(provider.assetsList[itemIndex])).onPress(() { + child: SlideTransition(position: slideAnimation, child: AssetTrackingListItemView(provider.assetsList[itemIndex], true)).onPress(() { Navigator.push(context, MaterialPageRoute(builder: (context) => MapTrackingPage(assetTrackingData: provider.assetsList[itemIndex]))); }), ); @@ -249,7 +242,7 @@ class _AssetTrackingPageState extends State with SingleTicker if (provider.isNextPageLoading) const Padding( padding: EdgeInsets.symmetric(vertical: 16), - child: Center(child: CircularProgressIndicator()), + child: ALoading(), ), ], ), From b018e7a4206afd43f03e07265fe68f175e30036d Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 <50428976+WaseemAbbasi22@users.noreply.github.com> Date: Mon, 21 Sep 2026 14:34:53 +0300 Subject: [PATCH 3/4] pagination added --- lib/modules/asset_tracking/asset_tracking_item_view.dart | 2 +- lib/modules/asset_tracking/asset_tracking_page.dart | 7 +------ lib/modules/asset_tracking/asset_tracking_provider.dart | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/modules/asset_tracking/asset_tracking_item_view.dart b/lib/modules/asset_tracking/asset_tracking_item_view.dart index 0b726413..8b278203 100644 --- a/lib/modules/asset_tracking/asset_tracking_item_view.dart +++ b/lib/modules/asset_tracking/asset_tracking_item_view.dart @@ -42,7 +42,7 @@ class AssetTrackingListItemView extends StatelessWidget { arrowMsg: isGridView ? "" : "View on map", ), if (isGridView) ...[ - 4.height, + 5.height, InfoTextWidget( label: "View on map", value: '', diff --git a/lib/modules/asset_tracking/asset_tracking_page.dart b/lib/modules/asset_tracking/asset_tracking_page.dart index a4c1a28e..9432584a 100644 --- a/lib/modules/asset_tracking/asset_tracking_page.dart +++ b/lib/modules/asset_tracking/asset_tracking_page.dart @@ -192,18 +192,13 @@ class _AssetTrackingPageState extends State with SingleTicker padding: const EdgeInsets.all(16), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, - childAspectRatio: 1.2, // need to fix this it's not flexiable with content.. + childAspectRatio: 1.1, // need to fix this it's not flexiable with content.. crossAxisSpacing: 12, mainAxisSpacing: 12, ), - itemCount: provider.isLoading ? 6 : provider.assetsList.length, - // separatorBuilder: (listContext, itemIndex) => 12.height, - itemBuilder: (listContext, itemIndex) { if (provider.isLoading) return const SizedBox().toAssetListShimmer(listContext, provider.isLoading); - - // Calculate staggered animation delay final delay = itemIndex * 0.08; final animation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( diff --git a/lib/modules/asset_tracking/asset_tracking_provider.dart b/lib/modules/asset_tracking/asset_tracking_provider.dart index ae21666c..9e148441 100644 --- a/lib/modules/asset_tracking/asset_tracking_provider.dart +++ b/lib/modules/asset_tracking/asset_tracking_provider.dart @@ -74,7 +74,7 @@ class AssetTrackingProvider extends ChangeNotifier { assetsList = responseAssetList; // assetInventoryResponse = newResponse; } - final int totalRows = (jsonData["totalRows"] as int?) ?? assetsList.length; + final int totalRows = (jsonData["totalRows"] as int?) ?? assetsList.length; nextPage = (assetsList.length) < totalRows; } else { if (loadMore) pageNo -= 1; From 74cfd942c87b6000291256f2c53646ad59df0c23 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 <50428976+WaseemAbbasi22@users.noreply.github.com> Date: Thu, 24 Sep 2026 11:25:01 +0300 Subject: [PATCH 4/4] pagination and filters added --- lib/controllers/api_routes/urls.dart | 4 + lib/main.dart | 7 + .../asset_tracking/asset_tracking_page.dart | 229 +++++++++++++++- .../asset_tracking_provider.dart | 22 +- .../asset_tracking_search_screen.dart | 253 ++++++++++++++++++ .../asset_tracking/filter_provider.dart | 182 +++++++++++++ .../models/asset_tracking_search_model.dart | 64 +++++ 7 files changed, 745 insertions(+), 16 deletions(-) create mode 100644 lib/modules/asset_tracking/asset_tracking_search_screen.dart create mode 100644 lib/modules/asset_tracking/filter_provider.dart create mode 100644 lib/modules/asset_tracking/models/asset_tracking_search_model.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 645db97d..d2b95192 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -637,5 +637,9 @@ class URLs { static get getPenguinDepartments => "$_baseUrl/PenguinIN/departments"; static get getPenguinBuildings => "$_baseUrl/PenguinIN/buildings"; static get getPenguinFloors => "$_baseUrl/PenguinIN/floors"; + static get getPenguinStatus => "$_baseUrl/PenguinIN/statuses"; + static get getPenguinAssetTypes => "$_baseUrl/PenguinIN/assetTypes"; + static get getPenguinTagStatusLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=3037"; + static get getPenguinTagAssignmentLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=3033"; } diff --git a/lib/main.dart b/lib/main.dart index 9a50b7ae..091514cd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -137,6 +137,7 @@ import 'controllers/providers/settings/setting_provider.dart'; import 'dashboard_latest/dashboard_provider.dart'; import 'l10n/app_localizations.dart'; import 'modules/asset_tracking/asset_tracking_provider.dart'; +import 'modules/asset_tracking/filter_provider.dart'; import 'modules/demo_module/demo_document_lookup_provider.dart'; import 'modules/incident_module/create_incident_request_page.dart'; import 'modules/incident_module/incident_lookup_provider.dart'; @@ -405,6 +406,12 @@ class MyApp extends StatelessWidget { // UTILITY PROVIDERS (1) ChangeNotifierProvider(create: (_) => OracleCodeProvider(), lazy: true), ChangeNotifierProvider(create: (_) => AssetTrackingProvider(), lazy: true), + ChangeNotifierProvider(create: (_) => TypeProvider(), lazy: true), + ChangeNotifierProvider(create: (_) => TagAssignmentProvider(), lazy: true), + ChangeNotifierProvider(create: (_) => TagStatusProvider(), lazy: true), + ChangeNotifierProvider(create: (_) => LastSeenProvider(), lazy: true), + ChangeNotifierProvider(create: (_) => AssetTrackingStatusProvider(), lazy: true), + ChangeNotifierProvider(create: (_) => AssetTrackingDepartmentProvider(), lazy: true), ], child: GestureDetector( onTap: () { diff --git a/lib/modules/asset_tracking/asset_tracking_page.dart b/lib/modules/asset_tracking/asset_tracking_page.dart index 9432584a..a6c09649 100644 --- a/lib/modules/asset_tracking/asset_tracking_page.dart +++ b/lib/modules/asset_tracking/asset_tracking_page.dart @@ -1,10 +1,14 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/asset_tracking/asset_tracking_provider.dart'; +import 'package:test_sa/modules/asset_tracking/asset_tracking_search_screen.dart'; +import 'package:test_sa/modules/asset_tracking/models/asset_tracking_search_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; @@ -25,6 +29,7 @@ class _AssetTrackingPageState extends State with SingleTicker int selectedIndex = 1; late AnimationController _animationController; late AssetTrackingProvider assetTrackingProvider; + AssetTrackingSearchModel? _searchModel; @override void initState() { @@ -41,20 +46,51 @@ class _AssetTrackingPageState extends State with SingleTicker }); } - Future getAssetsFromPenguin({bool loadMore = false}) async { - await assetTrackingProvider.getAssetsFromPenguin( - loadMore: loadMore, - ); + Future getAssetsFromPenguin({bool loadMore = false, AssetTrackingSearchModel? searchModel}) async { + await assetTrackingProvider.getAssetsFromPenguin(loadMore: loadMore, searchModel: searchModel ?? _searchModel); } @override Widget build(BuildContext context) { return Scaffold( - appBar: const DefaultAppBar(title: "Live Asset Tracking"), + appBar: DefaultAppBar( + title: "Live Asset Tracking", + actions: [ + IconButton( + icon: Icon(Icons.search, color: AppColor.icon2Color(context)), + padding: EdgeInsets.zero, + iconSize: 20, + visualDensity: VisualDensity.compact, + tooltip: "Search", + onPressed: () async { + final result = await Navigator.push( + context, + CupertinoPageRoute( + fullscreenDialog: true, + builder: (context) => AssetTrackingSearchScreen( + searchModel: _searchModel, + ), + ), + ); + + if (result != null) { + assetTrackingProvider.reset(); + setState(() { + _searchModel = result; + }); + await assetTrackingProvider.getAssetsFromPenguin( + searchModel: result, + ); + } + }, + ), + ], + ), body: Column( // crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ + if (_filterIsNotEmpty()) _buildActiveFiltersChips(), SizedBox( width: double.infinity, child: SegmentedButton( @@ -244,4 +280,187 @@ class _AssetTrackingPageState extends State with SingleTicker ); }); } + + Widget _buildActiveFiltersChips() { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + decoration: BoxDecoration( + color: AppColor.background(context), + border: Border( + bottom: BorderSide(color: AppColor.borderColor(context), width: 1), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 4, + children: [ + Text( + 'Active Filters', + style: AppTextStyles.tinyFont2.copyWith(color: AppColor.labelTextStyleColor(context), fontWeight: FontWeight.w600), + ), + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + spacing: 16, + children: [ + SizedBox( + height: 40.toScreenHeight, + child: ListView.separated( + scrollDirection: Axis.horizontal, + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => _getActiveFilterChips()[index], + separatorBuilder: (cxt, index) => 8.width, + itemCount: _getActiveFilterChips().length, + ), + ).expanded, + TextButton( + onPressed: () { + setState(() { + _searchModel = AssetTrackingSearchModel(); + getAssetsFromPenguin(); + }); + }, + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + child: Text( + 'Clear Filters', + style: AppTextStyles.tinyFont.copyWith(color: AppColor.red30), + ), + ), + ], + ) + ], + ), + ); + } + + Widget _buildFilterChip({required String label, required VoidCallback onDelete}) { + return Theme( + data: Theme.of(context).copyWith(splashColor: Colors.transparent, highlightColor: Colors.transparent), + child: Chip( + backgroundColor: AppColor.backgroundTabBarColor(context), + side: BorderSide(color: AppColor.border2Color(context)), + visualDensity: VisualDensity.compact, + label: Text(label), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30.0), + ), + labelStyle: AppTextStyles.tinyFont2.copyWith( + color: AppColor.labelTextStyleColor(context), + ), + deleteIconColor: AppColor.icon2Color(context), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + onDeleted: onDelete, + ), + ); + } + + List _getActiveFilterChips() { + final chips = []; + + // Search + if (_searchModel?.search?.isNotEmpty ?? false) { + chips.add( + _buildFilterChip( + label: 'Search: ${_searchModel?.search}', + onDelete: () { + setState(() { + _searchModel?.search = null; + getAssetsFromPenguin(searchModel: _searchModel); + }); + }, + ), + ); + } + if (_searchModel?.types?.isNotEmpty ?? false) { + for (final type in _searchModel?.types ?? []) { + chips.add( + _buildFilterChip( + label: 'Type: ${type.name}', + onDelete: () { + setState(() { + _searchModel?.types!.remove(type); + getAssetsFromPenguin(searchModel: _searchModel); + }); + }, + ), + ); + } + } + if (_searchModel?.status?.isNotEmpty ?? false) { + for (final status in _searchModel?.status ?? []) { + chips.add( + _buildFilterChip( + label: 'Status: ${status.name}', + onDelete: () { + setState(() { + _searchModel?.status!.remove(status); + getAssetsFromPenguin(searchModel: _searchModel); + }); + }, + ), + ); + } + } + + if (_searchModel?.departments?.isNotEmpty ?? false) { + for (final department in _searchModel?.departments ?? []) { + chips.add( + _buildFilterChip( + label: 'Department: ${department.name}', + onDelete: () { + setState(() { + _searchModel?.departments?.remove(department); + getAssetsFromPenguin(searchModel: _searchModel); + }); + }, + ), + ); + } + } + + // Start Date + if (_searchModel?.startDate?.isNotEmpty ?? false) { + chips.add( + _buildFilterChip( + label: 'From: ${_searchModel?.startDate?.toAssetDetailsFormat}', + onDelete: () { + setState(() { + _searchModel?.startDate = null; + getAssetsFromPenguin(searchModel: _searchModel); + }); + }, + ), + ); + } + + // End Date + if (_searchModel?.endDate?.isNotEmpty ?? false) { + chips.add( + _buildFilterChip( + label: 'To: ${_searchModel?.endDate?.toAssetDetailsFormat}', + onDelete: () { + setState(() { + _searchModel?.endDate = null; + getAssetsFromPenguin(searchModel: _searchModel); + }); + }, + ), + ); + } + + return chips; + } + + bool _filterIsNotEmpty() { + return (_searchModel?.search?.isNotEmpty ?? false) || + (_searchModel?.types != null && _searchModel!.types!.isNotEmpty) || + (_searchModel?.status != null && _searchModel!.status!.isNotEmpty) || + (_searchModel?.departments != null && _searchModel!.departments!.isNotEmpty) || + (_searchModel?.startDate != null && _searchModel!.startDate!.isNotEmpty) || + (_searchModel?.endDate != null && _searchModel!.endDate!.isNotEmpty); + } + } diff --git a/lib/modules/asset_tracking/asset_tracking_provider.dart b/lib/modules/asset_tracking/asset_tracking_provider.dart index 9e148441..e5845573 100644 --- a/lib/modules/asset_tracking/asset_tracking_provider.dart +++ b/lib/modules/asset_tracking/asset_tracking_provider.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/modules/asset_tracking/models/asset_tracking_search_model.dart'; import 'models/asset_tracking_model.dart'; import 'models/floor_map_model.dart'; @@ -45,34 +46,35 @@ class AssetTrackingProvider extends ChangeNotifier { notifyListeners(); } - Future getAssetsFromPenguin({bool loadMore = false}) async { + Future getAssetsFromPenguin({bool loadMore = false,AssetTrackingSearchModel? searchModel}) async { if (isLoading || isNextPageLoading) return -2; if (loadMore) { isNextPageLoading = true; pageNo += 1; } else { isLoading = true; - pageNo = 1; // reset pagination + pageNo = 1; } notifyListeners(); try { - final payload = {"pageSize": pageItemNumber, "pageNumber": pageNo}; + final Map payload = { + "pageSize": pageItemNumber, + "pageNumber": pageNo, + }; + + if (searchModel != null) { + payload.addAll(searchModel.toJson()); + } final response = await ApiManager.instance.post(URLs.getAssetsFromPenguin, body: payload); if (response.statusCode >= 200 && response.statusCode < 300) { final Map jsonData = json.decode(response.body); List list = jsonData["data"] ?? []; List responseAssetList = list.map((item) => AssetTrackingModel.fromJson(item)).toList(); - // assetsList.addAll(list.map((item) => AssetTrackingModel.fromJson(item)).toList()); - // if (jsonData["totalRows"] <= assetsList.length) { - // nextPage = true; - // } if (loadMore) { assetsList.addAll(responseAssetList); - // assetInventoryResponse?.totalRows = newResponse.totalRows; } else { assetsList = responseAssetList; - // assetInventoryResponse = newResponse; } final int totalRows = (jsonData["totalRows"] as int?) ?? assetsList.length; nextPage = (assetsList.length) < totalRows; @@ -87,8 +89,6 @@ class AssetTrackingProvider extends ChangeNotifier { if (loadMore) pageNo -= 1; isLoading = false; isNextPageLoading = false; - // stateCode = -1; - // nextPage = false; notifyListeners(); return -1; } diff --git a/lib/modules/asset_tracking/asset_tracking_search_screen.dart b/lib/modules/asset_tracking/asset_tracking_search_screen.dart new file mode 100644 index 00000000..b9cd95bf --- /dev/null +++ b/lib/modules/asset_tracking/asset_tracking_search_screen.dart @@ -0,0 +1,253 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_tracking/filter_provider.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; +import '../../../new_views/common_widgets/default_app_bar.dart'; +import 'models/asset_tracking_search_model.dart'; + +class AssetTrackingSearchScreen extends StatefulWidget { + static const String id = "asset_tracking_screen"; + AssetTrackingSearchModel? searchModel; + + AssetTrackingSearchScreen({Key? key, this.searchModel}) : super(key: key); + + @override + State createState() => _AssetTrackingSearchScreenState(); +} + +class _AssetTrackingSearchScreenState extends State { + late AssetTrackingSearchModel searchModel; + final GlobalKey _formKey = GlobalKey(); + late TextEditingController _searchController; + + @override + void initState() { + searchModel = widget.searchModel ?? AssetTrackingSearchModel(); + _searchController = TextEditingController(text: searchModel.search); + super.initState(); + } + + @override + void dispose() { + _searchController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: DefaultAppBar( + title: context.translation.search, + showBackButtonAsCancel: true, + actions: [ + if (_showResetButton()) + TextButton( + onPressed: () { + setState(() { + _searchController.text = ""; + searchModel = AssetTrackingSearchModel(); + + }); + }, + style: TextButton.styleFrom(padding: EdgeInsets.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap), + child: Text( + 'Clear Filters', + style: AppTextStyles.bodyText2.copyWith(color: AppColor.red30), + ), + ).paddingOnly(start: 16, end: 16), + ], + ), + body: Form( + key: _formKey, + child: SafeArea( + child: Column( + children: [ + ListView( + padding: const EdgeInsets.all(16), + children: [ + context.translation.searchBy.heading5(context).custom(color: AppColor.textStyleColor(context)), + 4.height, + context.translation.searchByDesc.bodyText2(context).custom(color: AppColor.lightTextColor(context)), + 16.height, + AppTextFormField( + controller: _searchController, + labelText: context.translation.search, + onChange: (text) { + _searchController.text = text; + _searchController.selection = TextSelection.fromPosition(TextPosition(offset: _searchController.text.length)); + setState(() {}); + }, + onSaved: (value) { + searchModel.search = value; + }, + ), + 8.height, + MultipleItemDropDownMenu( + context: context, + title: 'Type', + initialValue: searchModel.types != null ? searchModel.types! : [], + showAsBottomSheet: true, + showShadow: true, + height: 56.toScreenHeight, + showCancel: true, + onSelect: (value) { + if (value != null) { + setState(() { + searchModel.types = value; + }); + } + }, + ), + 8.height, + MultipleItemDropDownMenu( + context: context, + title: 'Department', + initialValue: searchModel.departments != null ? searchModel.departments! : [], + showAsBottomSheet: true, + showShadow: true, + height: 56.toScreenHeight, + showCancel: true, + onSelect: (value) { + if (value != null) { + setState(() { + searchModel.departments = value; + }); + } + }, + ), + 8.height, + MultipleItemDropDownMenu( + context: context, + title: 'Status', + initialValue: searchModel.status != null ? searchModel.status! : [], + showAsBottomSheet: true, + showShadow: true, + height: 56.toScreenHeight, + showCancel: true, + onSelect: (value) { + if (value != null) { + setState(() { + searchModel.status = value; + }); + } + }, + ), + 8.height, + // MultipleItemDropDownMenu( + // context: context, + // title: 'Last Seen', + // initialValue: searchModel.lastSeen != null ? searchModel.lastSeen! : [], + // showAsBottomSheet: true, + // showShadow: true, + // height: 56.toScreenHeight, + // showCancel: true, + // onSelect: (value) { + // if (value != null) { + // setState(() { + // searchModel.lastSeen = value; + // }); + // } + // }, + // ), + // 8.height, + // MultipleItemDropDownMenu( + // context: context, + // title: 'Tag Status', + // initialValue: searchModel.tagStatus != null ? searchModel.tagStatus! : [], + // showAsBottomSheet: true, + // showShadow: true, + // height: 56.toScreenHeight, + // showCancel: true, + // onSelect: (value) { + // if (value != null) { + // setState(() { + // searchModel.tagStatus = value; + // }); + // } + // }, + // ), + // 8.height, + // MultipleItemDropDownMenu( + // context: context, + // title: 'Tag Assignment', + // initialValue: searchModel.tagAssignment != null ? searchModel.tagAssignment! : [], + // showAsBottomSheet: true, + // showShadow: true, + // height: 56.toScreenHeight, + // showCancel: true, + // onSelect: (value) { + // if (value != null) { + // setState(() { + // searchModel.tagAssignment = value; + // }); + // } + // }, + // ), + 8.height, + InfoHeader16Widget('Last Seen'), + 8.height, + Row( + children: [ + ADatePicker( + label: context.translation.from, + from: DateTime(2000), + date: DateTime.tryParse(searchModel.startDate ?? ""), + onDatePicker: (date) { + setState(() { + searchModel.startDate = date.toIso8601String(); + }); + }, + ).expanded, + 8.width, + ADatePicker( + label: context.translation.to, + from: DateTime(2000), + date: DateTime.tryParse(searchModel.endDate ?? ""), + onDatePicker: (date) { + setState(() { + searchModel.endDate = date.toIso8601String(); + }); + }, + ).expanded, + ], + ), + ], + ).expanded, + FooterActionButton.footerContainer(context: context, child: AppFilledButton(onPressed: _search, label: context.translation.search)), + ], + ), + ), + ), + ); + } + + void _search() { + if (!_formKey.currentState!.validate()) { + return; + } + _formKey.currentState!.save(); + Navigator.pop(context, searchModel); + } + + bool _showResetButton() { + return (_searchController.text.isNotEmpty) || + // (searchModel.tagAssignment != null && searchModel.tagAssignment!.isNotEmpty) || + // (searchModel.tagStatus != null && searchModel.tagStatus!.isNotEmpty) || + // (searchModel.lastSeen != null && searchModel.lastSeen!.isNotEmpty) || + (searchModel.types != null && searchModel.types!.isNotEmpty) || + (searchModel.status != null && searchModel.status!.isNotEmpty) || + (searchModel.departments != null && searchModel.departments!.isNotEmpty)|| + (searchModel.startDate != null && searchModel.startDate!.isNotEmpty) || + (searchModel.endDate != null && searchModel.endDate!.isNotEmpty); + } +} diff --git a/lib/modules/asset_tracking/filter_provider.dart b/lib/modules/asset_tracking/filter_provider.dart new file mode 100644 index 00000000..bdb84209 --- /dev/null +++ b/lib/modules/asset_tracking/filter_provider.dart @@ -0,0 +1,182 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +import '../../controllers/api_routes/api_manager.dart'; +import '../../controllers/api_routes/urls.dart'; + +class AssetTrackingDepartmentProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getPenguinDepartments,); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final List listJson = json.decode(response.body)["data"] ?? []; + + items = listJson.map((item) { + return Lookup.fromJson({ + ...item, + "name": item["label"], + }); + }).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} + +class AssetTrackingStatusProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getPenguinStatus); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final List listJson = json.decode(response.body)["data"] ?? []; + + items = listJson.map((item) { + return Lookup.fromJson({ + ...item, + "name": item["label"], + }); + }).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} + +class LastSeenProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.post(URLs.getDepartments, body: {"pageSize": 50}); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List listJson = json.decode(response.body)["data"]; + items = listJson.map((department) => Lookup.fromJson(department)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} + +class TagStatusProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getPenguinTagStatusLookup); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List listJson = json.decode(response.body)["data"]; + items = listJson.map((department) => Lookup.fromJson(department)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} + +class TagAssignmentProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getPenguinTagAssignmentLookup); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List listJson = json.decode(response.body)["data"]; + items = listJson.map((department) => Lookup.fromJson(department)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} + +class TypeProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getPenguinAssetTypes,); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + final List listJson = json.decode(response.body)["data"] ?? []; + + items = listJson.map((item) { + return Lookup.fromJson({ + ...item, + "name": item["label"], + }); + }).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} diff --git a/lib/modules/asset_tracking/models/asset_tracking_search_model.dart b/lib/modules/asset_tracking/models/asset_tracking_search_model.dart new file mode 100644 index 00000000..76457fad --- /dev/null +++ b/lib/modules/asset_tracking/models/asset_tracking_search_model.dart @@ -0,0 +1,64 @@ +import 'package:test_sa/models/lookup.dart'; + +class AssetTrackingSearchModel { + AssetTrackingSearchModel({ + this.search, + this.tagStatus, + this.lastSeen, + this.tagAssignment, + this.types, + this.departments, + this.status, + this.startDate, + this.endDate, + }); + + String? search; + List? tagStatus; + List? lastSeen; + List? tagAssignment; + List? departments; + List? types; + List? status; + String? startDate, endDate; + + Map toJson() { + final map = {}; + + if (search != null && search!.trim().isNotEmpty) { + map['searchString'] = search!.trim(); + } + + if (tagStatus?.isNotEmpty == true) { + map['tagStatusIds'] = tagStatus!.map((e) => e.id).toList(); + } + + if (lastSeen?.isNotEmpty == true) { + map['lastSeenIds'] = lastSeen!.map((e) => e.id).toList(); + } + + if (tagAssignment?.isNotEmpty == true) { + map['tagAssignmentIds'] = tagAssignment!.map((e) => e.id).toList(); + } + + if (types?.isNotEmpty == true) { + map['typeIds'] = types!.map((e) => e.id).toList(); + } + + if (departments?.isNotEmpty == true) { + map['departmentIds'] = departments!.map((e) => e.id).toList(); + } + + if (status?.isNotEmpty == true) { + map['statusIds'] = status!.map((e) => e.id).toList(); + } + if (startDate != null && startDate!.trim().isNotEmpty) { + map['lastSeenFrom'] = startDate!.trim(); + } + if (endDate != null && endDate!.trim().isNotEmpty) { + map['lastSeenTo'] = endDate!.trim(); + } + + return map; + } +} \ No newline at end of file