diff --git a/lib/view_models/your_tenders_view_model.dart b/lib/view_models/your_tenders_view_model.dart index c18ca63..a2e87e3 100644 --- a/lib/view_models/your_tenders_view_model.dart +++ b/lib/view_models/your_tenders_view_model.dart @@ -19,6 +19,7 @@ class YourTendersViewModel with ChangeNotifier { String? errorMessage; TenderApprovalsResponse? data; LikedTendersResponse? likedTendersData; + // Pagination state for feedback lists bool isLoadingMore = false; bool hasMore = true; @@ -31,6 +32,7 @@ class YourTendersViewModel with ChangeNotifier { bool hasMoreTenders = true; int _tendersOffset = 0; final int _tendersLimit = 10; + // Filter States DateTimeRange? selectedDateRange; String selectedStatus = 'All'; @@ -118,11 +120,12 @@ class YourTendersViewModel with ChangeNotifier { required String feedbackType, bool reset = false, }) async { - if (reset) { - _offset = 0; - hasMore = true; - _currentFeedbackType = feedbackType; - } +if (reset) { + _offset = (currentPage - 1) * _limit; + hasMore = true; + _currentFeedbackType = feedbackType; +} + if (!reset && (isLoadingMore || !hasMore)) { return; @@ -258,39 +261,66 @@ class YourTendersViewModel with ChangeNotifier { notifyListeners(); } - Future callWithFilter() async { - // Clear data before applying filter - _clearAllData(); +Future callWithFilter() async { + likedTendersData = null; + data = null; + isLoading = true; + notifyListeners(); - // Make fresh request based on selected status - if (selectedStatus == YourTendersStrings.all) { - final requestModel = GetTendersRequestModel( - status: '', - createdFrom: startDateUnix, - createdTo: endDateUnix, - limit: _tendersLimit, - offset: 0, - ); - await getTenders(requestModel: requestModel, reset: true); - } else if (selectedStatus == YourTendersStrings.tendersSubmitted) { - final requestModel = GetTendersRequestModel( - status: TenderApprovalStatus.submitted.value, - createdFrom: startDateUnix, - createdTo: endDateUnix, - limit: _tendersLimit, - offset: 0, - ); - await getTenders(requestModel: requestModel, reset: true); - } else if (selectedStatus == YourTendersStrings.likeTenders) { - await getTendersFeedback( - feedbackType: TenderFeedback.liked.value, - reset: true, - ); - } else if (selectedStatus == YourTendersStrings.dislikeTenders) { - await getTendersFeedback( - feedbackType: TenderFeedback.disliked.value, - reset: true, - ); - } + if (selectedStatus == YourTendersStrings.all) { + final requestModel = GetTendersRequestModel( + status: '', + createdFrom: startDateUnix, + createdTo: endDateUnix, + limit: _tendersLimit, + offset: _tendersOffset, + ); + await getTenders(requestModel: requestModel, reset: true); + } else if (selectedStatus == YourTendersStrings.tendersSubmitted) { + final requestModel = GetTendersRequestModel( + status: TenderApprovalStatus.submitted.value, + createdFrom: startDateUnix, + createdTo: endDateUnix, + limit: _tendersLimit, + offset: _tendersOffset, + ); + await getTenders(requestModel: requestModel, reset: true); + } else if (selectedStatus == YourTendersStrings.likeTenders) { + await getTendersFeedback( + feedbackType: TenderFeedback.liked.value, + reset: true, + ); + } else if (selectedStatus == YourTendersStrings.dislikeTenders) { + await getTendersFeedback( + feedbackType: TenderFeedback.disliked.value, + reset: true, + ); + } +} + + + int currentPage = 1; + + int get totalPages { + if (likedTendersData?.data?.meta?.pages != null) { + return likedTendersData!.data!.meta!.pages!; + } + if (data?.data?.metadata?.pages != null) { + return data!.data!.metadata!.pages!; + } + return 1; + } + + Future jumpToPage(int page) async { + currentPage = page; + _offset = (page - 1) * _limit; + _tendersOffset = (page - 1) * _tendersLimit; + + likedTendersData = null; + data = null; + hasMore = true; + hasMoreTenders = true; + + await callWithFilter(); } } diff --git a/lib/views/home/pages/t_home_page.dart b/lib/views/home/pages/t_home_page.dart index 8c7f835..33eb811 100644 --- a/lib/views/home/pages/t_home_page.dart +++ b/lib/views/home/pages/t_home_page.dart @@ -128,8 +128,7 @@ class TabletHomePage extends StatelessWidget { width: double.infinity, height: 148, onTap: () { - //YourTendersRouteData().push(context); - NotificationRouteData().push(context); + YourTendersRouteData().push(context); }, ), ), diff --git a/lib/views/your_tenders/pages/your_tenders_desktop_page.dart b/lib/views/your_tenders/pages/your_tenders_desktop_page.dart index 1b1ee5c..1f9a9d6 100644 --- a/lib/views/your_tenders/pages/your_tenders_desktop_page.dart +++ b/lib/views/your_tenders/pages/your_tenders_desktop_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/constants/tender_feedback.dart'; import 'package:tm_app/core/theme/colors.dart'; +import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/view_models/your_tenders_view_model.dart'; import 'package:tm_app/views/your_tenders/strings/your_tenders_strings.dart'; import 'package:tm_app/views/your_tenders/widgets/filter_button.dart'; @@ -38,26 +39,25 @@ class _YourTendersDesktopPageState extends State Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.backgroundColor, - body: Column( children: [ - DesktopNavigationWidget( - currentIndex: 1, // Tenders index - ), + DesktopNavigationWidget(currentIndex: 1), // Tenders index Expanded( child: SizedBox( width: 740, child: Column( children: [ - SizedBox(height: 64.0), - TabletDesktopAppbar(), - SizedBox(height: 20.0), - FilterButton(platformType: PlatformType.tabletDesktop), + SizedBox(height: 64.0.h()), + const TabletDesktopAppbar(), + SizedBox(height: 20.0.h()), + const FilterButton(platformType: PlatformType.tabletDesktop), Expanded( child: Consumer( builder: (context, viewModel, child) { - if (viewModel.isLoading) { + if (viewModel.isLoading && + (viewModel.data == null && + viewModel.likedTendersData == null)) { return const Center( child: CircularProgressIndicator( color: AppColors.secondary50, @@ -69,32 +69,140 @@ class _YourTendersDesktopPageState extends State return Center(child: Text(viewModel.errorMessage!)); } + Widget content; + if (viewModel.selectedStatus == YourTendersStrings.likeTenders && viewModel.likedTendersData != null) { - return LikedDislikedTendersList( + content = LikedDislikedTendersList( data: viewModel.likedTendersData!, status: TenderFeedback.liked.value, - isDesctop: true, + isDesktop: true, ); } else if (viewModel.selectedStatus == YourTendersStrings.dislikeTenders && viewModel.likedTendersData != null) { - return LikedDislikedTendersList( + content = LikedDislikedTendersList( data: viewModel.likedTendersData!, status: TenderFeedback.disliked.value, - isDesctop: true, - ); - } else if (viewModel.data != null) { - return TendersSubmitted( - approvedTenders: viewModel.data!, isDesktop: true, ); + } else if (viewModel.data != null) { + content = TendersSubmitted( + approvedTenders: viewModel.data!, + isDesktop: true, + isMobile: false, + ); } else { - return const Center( + content = const Center( child: Text(YourTendersStrings.noTenders), ); } + + return Column( + children: [ + Expanded(child: content), + SizedBox(height: 10.0.h()), + + Row( + children: [ + const Spacer(), + Text( + 'Page', + style: TextStyle( + fontSize: 13.0.sp(), + fontWeight: FontWeight.w300, + color: AppColors.grey60, + ), + ), + SizedBox(width: 10.0.w()), + InkWell( + onTap: () async { + final selectedPage = await showDialog( + context: context, + builder: (context) { + return AlertDialog( + backgroundColor: + AppColors.backgroundColor, + title: const Text('Select Page'), + content: SizedBox( + width: 200.0.w(), + height: 300.0.h(), + child: ListView.builder( + itemCount: viewModel.totalPages, + itemBuilder: (context, index) { + final pageNumber = index + 1; + return ListTile( + title: Text( + 'Page $pageNumber', + ), + onTap: + () => Navigator.pop( + context, + pageNumber, + ), + ); + }, + ), + ), + ); + }, + ); + + if (selectedPage != null) { + await viewModel.jumpToPage(selectedPage); + } + }, + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: AppColors.grey30, + width: 1, + ), + borderRadius: BorderRadius.circular(4), + ), + child: Row( + children: [ + SizedBox(width: 5.0.w()), + Text( + '${viewModel.currentPage}', + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.grey70, + ), + ), + SizedBox(width: 5.0.w()), + const Icon(Icons.arrow_drop_down), + SizedBox(width: 5.0.w()), + ], + ), + ), + ), + SizedBox(width: 5.0.w()), + Text( + 'of', + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + SizedBox(width: 5.0.w()), + Text( + '${viewModel.totalPages}', + style: TextStyle( + fontSize: 13.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + ], + ), + + SizedBox(height: 30.0.h()), + ], + ); }, ), ), diff --git a/lib/views/your_tenders/pages/your_tenders_mobile_page.dart b/lib/views/your_tenders/pages/your_tenders_mobile_page.dart index 27990e0..5be41f2 100644 --- a/lib/views/your_tenders/pages/your_tenders_mobile_page.dart +++ b/lib/views/your_tenders/pages/your_tenders_mobile_page.dart @@ -68,7 +68,7 @@ class _YourTendersMobilePageState extends State { child: LikedDislikedTendersList( data: viewModel.likedTendersData!, status: TenderFeedback.liked.value, - isDesctop: false, + isDesktop: false, ), ) else if (viewModel.selectedStatus == @@ -78,7 +78,7 @@ class _YourTendersMobilePageState extends State { child: LikedDislikedTendersList( data: viewModel.likedTendersData!, status: TenderFeedback.disliked.value, - isDesctop: false, + isDesktop: false, ), ) else if (viewModel.data != null) @@ -86,6 +86,7 @@ class _YourTendersMobilePageState extends State { child: TendersSubmitted( approvedTenders: viewModel.data!, isDesktop: false, + isMobile: true, ), ) else diff --git a/lib/views/your_tenders/pages/your_tenders_tablet_page.dart b/lib/views/your_tenders/pages/your_tenders_tablet_page.dart index e58341e..f84eaef 100644 --- a/lib/views/your_tenders/pages/your_tenders_tablet_page.dart +++ b/lib/views/your_tenders/pages/your_tenders_tablet_page.dart @@ -7,7 +7,6 @@ import 'package:tm_app/views/your_tenders/widgets/filter_button.dart'; import 'package:tm_app/views/your_tenders/widgets/liked_disliked_tenders_list.dart'; import 'package:tm_app/views/your_tenders/widgets/tablet_desktop_appbar.dart'; import 'package:tm_app/views/your_tenders/widgets/tenders_submitted.dart'; - import '../../../core/constants/tender_feedback.dart'; import '../../shared/tablet_navigation_widget.dart'; import '../../shared/tender_app_bar.dart'; @@ -43,9 +42,7 @@ class _YourTendersTabletPageState extends State key: key, backgroundColor: AppColors.backgroundColor, appBar: tabletAppBar(title: YourTendersStrings.yourTenders, key: key), - drawer: TabletNavigationWidget( - currentIndex: 1, // Home is index 0 - ), + drawer: TabletNavigationWidget(currentIndex: 1), body: Center( child: SizedBox( width: 720, @@ -57,19 +54,14 @@ class _YourTendersTabletPageState extends State child: TabletDesktopAppbar(), ), SizedBox(height: 24.0.h()), - // MainTabBar( - // controller: controller, - // titles: [ - // AppStrings.approvedTenders, - // AppStrings.tenderSubmitted, - // ], - // ), FilterButton(platformType: PlatformType.tabletDesktop), Expanded( child: Consumer( builder: (context, viewModel, child) { - if (viewModel.isLoading) { + if (viewModel.isLoading && + (viewModel.data == null && + viewModel.likedTendersData == null)) { return const Center( child: CircularProgressIndicator( color: AppColors.secondary50, @@ -81,32 +73,136 @@ class _YourTendersTabletPageState extends State return Center(child: Text(viewModel.errorMessage!)); } + Widget content; + if (viewModel.selectedStatus == YourTendersStrings.likeTenders && viewModel.likedTendersData != null) { - return LikedDislikedTendersList( + content = LikedDislikedTendersList( data: viewModel.likedTendersData!, status: TenderFeedback.liked.value, - isDesctop: false, + isDesktop: false, ); } else if (viewModel.selectedStatus == YourTendersStrings.dislikeTenders && viewModel.likedTendersData != null) { - return LikedDislikedTendersList( + content = LikedDislikedTendersList( data: viewModel.likedTendersData!, status: TenderFeedback.disliked.value, - isDesctop: false, - ); - } else if (viewModel.data != null) { - return TendersSubmitted( - approvedTenders: viewModel.data!, isDesktop: false, ); + } else if (viewModel.data != null) { + content = TendersSubmitted( + approvedTenders: viewModel.data!, + isDesktop: false, + isMobile: false, + ); } else { - return const Center( + content = const Center( child: Text(YourTendersStrings.noTenders), ); } + + return Column( + children: [ + Expanded(child: content), + SizedBox(height: 10.0.h()), + + Row( + children: [ + const Spacer(), + Text( + 'Page', + style: TextStyle( + fontSize: 13.0, + fontWeight: FontWeight.w300, + color: AppColors.grey60, + ), + ), + SizedBox(width: 10.0.w()), + InkWell( + onTap: () async { + final selectedPage = await showDialog( + context: context, + builder: (context) { + return AlertDialog( + backgroundColor: AppColors.backgroundColor, + title: const Text('Select Page'), + content: SizedBox( + width: 200.0.w(), + height: 300.0.h(), + child: ListView.builder( + itemCount: viewModel.totalPages, + itemBuilder: (context, index) { + final pageNumber = index + 1; + return ListTile( + title: Text('Page $pageNumber'), + onTap: () => Navigator.pop( + context, + pageNumber, + ), + ); + }, + ), + ), + ); + }, + ); + + if (selectedPage != null) { + await viewModel.jumpToPage(selectedPage); + } + }, + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: AppColors.grey30, + width: 1, + ), + borderRadius: BorderRadius.circular(4), + ), + child: Row( + children: [ + SizedBox(width: 5.0.w()), + Text( + '${viewModel.currentPage}', + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.grey70, + ), + ), + SizedBox(width: 5.0.w()), + const Icon(Icons.arrow_drop_down), + SizedBox(width: 5.0.w()), + ], + ), + ), + ), + SizedBox(width: 5.0), + Text( + 'of', + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + SizedBox(width: 5.0.w()), + Text( + '${viewModel.totalPages}', + style: TextStyle( + fontSize: 13.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + ], + ), + + const SizedBox(height: 30.0), + ], + ); }, ), ), diff --git a/lib/views/your_tenders/widgets/liked_disliked_tenders_list.dart b/lib/views/your_tenders/widgets/liked_disliked_tenders_list.dart index 2613cd1..c09d085 100644 --- a/lib/views/your_tenders/widgets/liked_disliked_tenders_list.dart +++ b/lib/views/your_tenders/widgets/liked_disliked_tenders_list.dart @@ -12,12 +12,12 @@ import '../../../core/constants/tender_feedback.dart'; class LikedDislikedTendersList extends StatefulWidget { final LikedTendersResponse data; final String status; - final bool isDesctop; + final bool isDesktop; const LikedDislikedTendersList({ required this.data, required this.status, - required this.isDesctop, + required this.isDesktop, super.key, }); @@ -86,7 +86,7 @@ class _LikedDislikedTendersListState extends State { padding: EdgeInsets.only(bottom: 16.0.h()), child: TenderCard( tender: feedback.tender!, - isDesktop: widget.isDesctop, + isDesktop: widget.isDesktop, status: widget.status, submissionMode: '', ), diff --git a/lib/views/your_tenders/widgets/tenders_submitted.dart b/lib/views/your_tenders/widgets/tenders_submitted.dart index 6141b10..f63f1fa 100644 --- a/lib/views/your_tenders/widgets/tenders_submitted.dart +++ b/lib/views/your_tenders/widgets/tenders_submitted.dart @@ -11,11 +11,13 @@ class TendersSubmitted extends StatefulWidget { const TendersSubmitted({ required this.approvedTenders, required this.isDesktop, + required this.isMobile, super.key, }); final TenderApprovalsResponse approvedTenders; final bool isDesktop; + final bool isMobile; @override State createState() => _TendersSubmittedState(); @@ -67,7 +69,7 @@ class _TendersSubmittedState extends State { tenders.length + (viewModel.isLoadingMoreTenders ? 1 : 0); return ListView.builder( - controller: _scrollController, + controller: widget.isMobile ? _scrollController : null, padding: EdgeInsets.symmetric( // horizontal: 24.0.w(), vertical: 15.0.h(),