diff --git a/lib/core/routes/app_shell/app_shell_screen.dart b/lib/core/routes/app_shell/app_shell_screen.dart index 15f9a75..d157f03 100644 --- a/lib/core/routes/app_shell/app_shell_screen.dart +++ b/lib/core/routes/app_shell/app_shell_screen.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; import 'package:tm_app/core/routes/app_shell/desktop_shell_page.dart'; import 'package:tm_app/core/routes/app_shell/mobile_shell_page.dart'; import 'package:tm_app/core/routes/app_shell/tablet_shell_page.dart'; +import 'package:tm_app/view_models/home_view_model.dart'; import 'package:tm_app/views/shared/responsive_builder.dart'; class AppShellScreen extends StatelessWidget { @@ -10,11 +12,12 @@ class AppShellScreen extends StatelessWidget { final StatefulNavigationShell navigationShell; - void _gotoBranch(int index) { + void _gotoBranch(int index, BuildContext context) { navigationShell.goBranch( index, initialLocation: index == navigationShell.currentIndex, ); + context.read().init(); } @override @@ -22,15 +25,15 @@ class AppShellScreen extends StatelessWidget { return ResponsiveBuilder( mobile: MobileShellPage( navigationShell: navigationShell, - onTap: _gotoBranch, + onTap: (value) => _gotoBranch(value, context), ), tablet: TabletShellPage( navigationShell: navigationShell, - onTap: _gotoBranch, + onTap: (value) => _gotoBranch(value, context), ), desktop: DesktopShellPage( navigationShell: navigationShell, - onTap: _gotoBranch, + onTap: (value) => _gotoBranch(value, context), ), ); } diff --git a/lib/view_models/home_view_model.dart b/lib/view_models/home_view_model.dart index 744c3d9..8ae0530 100644 --- a/lib/view_models/home_view_model.dart +++ b/lib/view_models/home_view_model.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:tm_app/core/utils/result.dart'; import 'package:tm_app/data/services/model/home/home_request/home_request_model.dart'; import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart'; -import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart'; import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart'; +import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart'; import 'package:tm_app/data/services/model/tender_data/tender_data.dart'; import '../data/repositories/home_repository.dart'; @@ -14,9 +14,7 @@ class HomeViewModel with ChangeNotifier { HomeViewModel({required HomeRepository homeRepository}) : _homeRepository = homeRepository { - getHome(homeRequestModel: HomeRequestModel(id: '1')); - getYourTenders(); - getApprovedStates(); + init(); } bool _isLoading = false; @@ -40,6 +38,11 @@ class HomeViewModel with ChangeNotifier { bool get isLoadingMore => _isLoadingMore; bool get hasMore => _hasMore; + void init() async { + await getApprovedStates(); + await getYourTenders(); + } + Future getHome({HomeRequestModel? homeRequestModel}) async { _isLoading = true; _errorMessage = null; @@ -120,9 +123,7 @@ class HomeViewModel with ChangeNotifier { } else { _tenders.clear(); _tenders.addAll( - data!.data! - .map((e) => e.tender) - .whereType(), + data!.data!.map((e) => e.tender).whereType(), ); } @@ -135,7 +136,8 @@ class HomeViewModel with ChangeNotifier { _isLoading = false; notifyListeners(); } - Future getApprovedStates() async { + + Future getApprovedStates() async { _isLoading = true; _errorMessage = null; notifyListeners(); diff --git a/lib/view_models/tender_detail_view_model.dart b/lib/view_models/tender_detail_view_model.dart index 61f5ed4..3f73acb 100644 --- a/lib/view_models/tender_detail_view_model.dart +++ b/lib/view_models/tender_detail_view_model.dart @@ -5,6 +5,8 @@ import 'package:tm_app/data/repositories/tenders_repository.dart'; import 'package:tm_app/data/services/model/tender_data/tender_data.dart'; import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart'; +import '../data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart'; +import '../data/services/model/tender_approvals_data/tender_approvals_data.dart'; import '../data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart'; class TenderDetailViewModel with ChangeNotifier { @@ -22,14 +24,17 @@ class TenderDetailViewModel with ChangeNotifier { bool _isRejectApprovalLoading = false; String? _errorMessage; TenderData? _tenderDetail; - + TenderApprovalsData? _tenderApprovalData; bool approvalStatus = false; + String _status = ''; bool get isLoading => _isLoading; bool get isSubmitApprovalLoading => _isSubmitApprovalLoading; bool get isRejectApprovalLoading => _isRejectApprovalLoading; String? get errorMessage => _errorMessage; TenderData? get tenderDetail => _tenderDetail; + TenderApprovalsData? get tenderApprovalData => _tenderApprovalData; + String get status => _status; Future getTenderDetail({required String id}) async { _isLoading = true; @@ -40,6 +45,7 @@ class TenderDetailViewModel with ChangeNotifier { switch (result) { case Ok(): _tenderDetail = result.value.data; + await getTenderApprovals(id); break; case Error(): _errorMessage = result.error.toString(); @@ -64,6 +70,7 @@ class TenderDetailViewModel with ChangeNotifier { switch (result) { case Ok(): approvalStatus = true; + _status = result.value.data?.status ?? ''; break; case Error(): _errorMessage = result.error.toString(); @@ -73,6 +80,7 @@ class TenderDetailViewModel with ChangeNotifier { _isSubmitApprovalLoading = false; notifyListeners(); _errorMessage = null; + approvalStatus = false; notifyListeners(); } @@ -90,6 +98,7 @@ class TenderDetailViewModel with ChangeNotifier { switch (result) { case Ok(): approvalStatus = true; + _status = result.value.data?.status ?? ''; break; case Error(): _errorMessage = result.error.toString(); @@ -99,6 +108,28 @@ class TenderDetailViewModel with ChangeNotifier { _isRejectApprovalLoading = false; notifyListeners(); _errorMessage = null; + approvalStatus = false; + notifyListeners(); + } + + Future getTenderApprovals(String tenderId) async { + _errorMessage = null; + notifyListeners(); + + final result = await _tendersRepository.getTenderApprovals( + tenderId: tenderId, + ); + switch (result) { + case Ok(): + _tenderApprovalData = result.value.data; + _status = result.value.data?.status ?? ''; + break; + case Error(): + _errorMessage = result.error.toString(); + break; + } + notifyListeners(); + _errorMessage = null; notifyListeners(); } } diff --git a/lib/view_models/tenders_view_model.dart b/lib/view_models/tenders_view_model.dart index 8b95fe4..cb974f4 100644 --- a/lib/view_models/tenders_view_model.dart +++ b/lib/view_models/tenders_view_model.dart @@ -231,6 +231,9 @@ class TendersViewModel with ChangeNotifier { } break; case Error(): + // Remove the tender from tenderApprovals if an error occurs for this tenderId + + tenderApprovals.removeWhere((a) => a.tenderId == tenderId); _errorMessage = result.error.toString(); break; } diff --git a/lib/views/detail/pages/detail_mobile_page.dart b/lib/views/detail/pages/detail_mobile_page.dart index e786e39..252a1ab 100644 --- a/lib/views/detail/pages/detail_mobile_page.dart +++ b/lib/views/detail/pages/detail_mobile_page.dart @@ -9,10 +9,60 @@ import 'package:tm_app/views/detail/widgets/tender_detail_card.dart'; import 'package:tm_app/views/detail/widgets/tender_detail_header.dart'; import 'package:tm_app/views/shared/tender_app_bar.dart'; -class TenderDetailMobilePage extends StatelessWidget { +class TenderDetailMobilePage extends StatefulWidget { final String tenderId; const TenderDetailMobilePage({required this.tenderId, super.key}); + @override + State createState() => _TenderDetailMobilePageState(); +} + +class _TenderDetailMobilePageState extends State { + late final TenderDetailViewModel viewModel; + @override + void initState() { + viewModel = context.read(); + viewModel.addListener(_viewModelListener); + super.initState(); + } + + void _viewModelListener() { + if (viewModel.status.isNotEmpty && + viewModel.status == 'approved' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('tender approved successfully!'))); + } + if (viewModel.status.isNotEmpty && + viewModel.status == 'unapproved' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('tender approve removed sucessfully!')), + ); + } + if (viewModel.status.isNotEmpty && + viewModel.status == 'rejected' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('tender rejected sucessfully!'))); + } + if (viewModel.status.isNotEmpty && + viewModel.status == 'unrejected' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('tender reject removed sucessfully!')), + ); + } + } + + @override + void dispose() { + viewModel.removeListener(_viewModelListener); + super.dispose(); + } + @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/views/detail/widgets/tender_detail_action.dart b/lib/views/detail/widgets/tender_detail_action.dart index 7e7f6af..3855fff 100644 --- a/lib/views/detail/widgets/tender_detail_action.dart +++ b/lib/views/detail/widgets/tender_detail_action.dart @@ -63,20 +63,27 @@ class TenderDetailActions extends StatelessWidget { backgroundColor: AppColors.primary30, textColor: AppColors.mainBlue, onPressed: () { - showModalBottomSheet( - isDismissible: true, - context: context, - builder: (context) { - return SelectSubmissionBottomSheet( - onConfirm: (value) { - viewModel.submitTenderApproval( - tenderId: detail.id!, - submissionMode: value, - ); - }, - ); - }, - ); + if (viewModel.status == 'approved') { + viewModel.submitTenderApproval( + tenderId: detail.id!, + submissionMode: 'self-apply', + ); + } else { + showModalBottomSheet( + isDismissible: true, + context: context, + builder: (context) { + return SelectSubmissionBottomSheet( + onConfirm: (value) { + viewModel.submitTenderApproval( + tenderId: detail.id!, + submissionMode: value, + ); + }, + ); + }, + ); + } }, ); }, diff --git a/lib/views/home/pages/m_home_page.dart b/lib/views/home/pages/m_home_page.dart index 274f39b..350b82c 100644 --- a/lib/views/home/pages/m_home_page.dart +++ b/lib/views/home/pages/m_home_page.dart @@ -13,9 +13,20 @@ import 'package:tm_app/views/shared/tender_app_bar.dart'; import '../widgets.dart'; -class MobileHomePage extends StatelessWidget { +class MobileHomePage extends StatefulWidget { const MobileHomePage({super.key}); + @override + State createState() => _MobileHomePageState(); +} + +class _MobileHomePageState extends State { + @override + void initState() { + // context.read().init(); + super.initState(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -32,8 +43,8 @@ class MobileHomePage extends StatelessWidget { return Center(child: Text(homeViewModel.errorMessage!)); } - if (homeViewModel.homeResponse != null && - homeViewModel.tenderApprovalsStateResponse != null) { + if (homeViewModel.tenderApprovalsStateResponse != null && + homeViewModel.data != null) { return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/views/home/progress_bar_column.dart b/lib/views/home/progress_bar_column.dart index 74e0a4a..d57ec15 100644 --- a/lib/views/home/progress_bar_column.dart +++ b/lib/views/home/progress_bar_column.dart @@ -91,7 +91,7 @@ class _ProgressBarColumnState extends State Widget _centerText() { return Center( child: Text( - '${widget.amount}%', + '${double.parse(widget.amount).round()}%', style: TextStyle( fontSize: 24.0.sp(), fontWeight: FontWeight.bold, diff --git a/lib/views/tenders/widgets/tender_card.dart b/lib/views/tenders/widgets/tender_card.dart index 78f8ace..5969df2 100644 --- a/lib/views/tenders/widgets/tender_card.dart +++ b/lib/views/tenders/widgets/tender_card.dart @@ -1,6 +1,7 @@ import 'package:country_flags/country_flags.dart'; import 'package:flutter/material.dart' hide DateUtils; import 'package:flutter_svg/svg.dart'; +import 'package:provider/provider.dart'; import 'package:tm_app/core/constants/strings.dart'; import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/data/services/model/tender_data/tender_data.dart'; @@ -9,6 +10,7 @@ import '../../../core/constants/assets.dart'; import '../../../core/theme/colors.dart'; import '../../../core/utils/date_utils.dart'; import '../../../core/utils/size_config.dart'; +import '../../../view_models/tenders_view_model.dart'; import 'tender_action_buttons_row.dart'; class TenderCard extends StatelessWidget { @@ -319,7 +321,13 @@ class TenderCard extends StatelessWidget { return InkWell( onTap: () { if (tender.id != null) { - TenderDetailRouteData(tenderId: tender.id!).push(context); + TenderDetailRouteData(tenderId: tender.id!).push(context).then(( + value, + ) { + if (context.mounted) { + context.read().getTenderApprovals(tender.id!); + } + }); } }, child: Container(