From e6b4720dcdb65ad06da66786ad5873354e156d01 Mon Sep 17 00:00:00 2001 From: AmirReza Jamali Date: Sat, 30 May 2026 16:48:05 +0330 Subject: [PATCH] Update iOS deployment target to 13.0, enhance Flutter integration, and improve tender submission flow - Changed the iOS deployment target from 12.0 to 13.0 in Podfile and project settings. - Updated AppDelegate to support implicit Flutter engine initialization. - Modified Info.plist to include scene configuration for multiple scenes. - Enhanced CompletionOfDocumentsRouteData to accept a tenderId parameter. - Implemented tender submission functionality in TenderDetailViewModel and updated UI components to reflect loading states and success/error messages. - Added new strings for submission success and error notifications. --- ios/Flutter/AppFrameworkInfo.plist | 2 - ios/Podfile | 2 +- ios/Runner.xcodeproj/project.pbxproj | 28 ++- .../xcshareddata/swiftpm/Package.resolved | 176 ++++++++++++++++++ .../xcshareddata/xcschemes/Runner.xcscheme | 20 ++ ios/Runner/AppDelegate.swift | 7 +- ios/Runner/Info.plist | 29 ++- lib/core/routes/app_routes.dart | 7 +- lib/core/routes/app_routes.g.dart | 14 +- lib/view_models/tender_detail_view_model.dart | 30 +++ lib/view_models/your_tenders_view_model.dart | 17 +- .../complectopn_of_documents_screen.dart | 11 +- .../pages/d_completion_of_documents_page.dart | 46 ++++- .../pages/m_completion_of_documents_page.dart | 42 ++++- .../pages/t_completion_of_documents_page.dart | 46 ++++- .../completion_of_documents_string.dart | 2 + .../detail/widgets/tender_detail_action.dart | 11 +- .../profile/strings/profile_strings.dart | 1 + lib/views/profile/widgets/main_data_tab.dart | 9 + 19 files changed, 445 insertions(+), 55 deletions(-) create mode 100644 ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 7c56964..391a902 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -20,7 +20,5 @@ ???? CFBundleVersion 1.0 - MinimumOSVersion - 12.0 diff --git a/ios/Podfile b/ios/Podfile index e549ee2..620e46e 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '12.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index d08bbb7..e13d49d 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -55,6 +56,7 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,6 +64,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -79,6 +82,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -142,6 +146,9 @@ productType = "com.apple.product-type.bundle.unit-test"; }; 97C146ED1CF9000F007C117D /* Runner */ = { + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( @@ -165,6 +172,9 @@ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + ); isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; @@ -346,7 +356,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -472,7 +482,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -523,7 +533,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -611,6 +621,18 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..7e63959 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,176 @@ +{ + "pins" : [ + { + "identity" : "abseil-cpp-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/abseil-cpp-binary.git", + "state" : { + "revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5", + "version" : "1.2024072200.0" + } + }, + { + "identity" : "app-check", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/app-check.git", + "state" : { + "revision" : "61b85103a1aeed8218f17c794687781505fbbef5", + "version" : "11.2.0" + } + }, + { + "identity" : "dkcamera", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKCamera", + "state" : { + "branch" : "master", + "revision" : "5c691d11014b910aff69f960475d70e65d9dcc96" + } + }, + { + "identity" : "dkimagepickercontroller", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKImagePickerController", + "state" : { + "branch" : "4.3.9", + "revision" : "0bdfeacefa308545adde07bef86e349186335915" + } + }, + { + "identity" : "dkphotogallery", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKPhotoGallery", + "state" : { + "branch" : "master", + "revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d" + } + }, + { + "identity" : "firebase-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/firebase-ios-sdk", + "state" : { + "revision" : "8d5b4189f1f482df8d5c58c9985ea70491ef5382", + "version" : "12.14.0" + } + }, + { + "identity" : "google-ads-on-device-conversion-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk", + "state" : { + "revision" : "9bfcc6cf435b2e7c5562c1900b8680c594fa9a64", + "version" : "3.6.0" + } + }, + { + "identity" : "googleappmeasurement", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleAppMeasurement.git", + "state" : { + "revision" : "219e564a8510e983e675c94f77f7f7c50049f22d", + "version" : "12.14.0" + } + }, + { + "identity" : "googledatatransport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleDataTransport.git", + "state" : { + "revision" : "617af071af9aa1d6a091d59a202910ac482128f9", + "version" : "10.1.0" + } + }, + { + "identity" : "googleutilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleUtilities.git", + "state" : { + "revision" : "60da361632d0de02786f709bdc0c4df340f7613e", + "version" : "8.1.0" + } + }, + { + "identity" : "grpc-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/grpc-binary.git", + "state" : { + "revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6", + "version" : "1.69.1" + } + }, + { + "identity" : "gtm-session-fetcher", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/gtm-session-fetcher.git", + "state" : { + "revision" : "c0ac7575d70050c2973ba2318bd5af47f8e8153a", + "version" : "5.3.0" + } + }, + { + "identity" : "interop-ios-for-google-sdks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/interop-ios-for-google-sdks.git", + "state" : { + "revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe", + "version" : "101.0.0" + } + }, + { + "identity" : "leveldb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/leveldb.git", + "state" : { + "revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1", + "version" : "1.22.5" + } + }, + { + "identity" : "nanopb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/nanopb.git", + "state" : { + "revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1", + "version" : "2.30910.0" + } + }, + { + "identity" : "promises", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/promises.git", + "state" : { + "revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac", + "version" : "2.4.0" + } + }, + { + "identity" : "sdwebimage", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SDWebImage/SDWebImage", + "state" : { + "revision" : "2de3a496eaf6df9a1312862adcfd54acd73c39c0", + "version" : "5.21.7" + } + }, + { + "identity" : "swiftygif", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kirualex/SwiftyGif.git", + "state" : { + "revision" : "4430cbc148baa3907651d40562d96325426f409a", + "version" : "5.4.5" + } + }, + { + "identity" : "tocropviewcontroller", + "kind" : "remoteSourceControl", + "location" : "https://github.com/TimOliver/TOCropViewController", + "state" : { + "revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e", + "version" : "2.8.0" + } + } + ], + "version" : 2 +} diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 15cada4..c3fedb2 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + Bool { - GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 3abf06c..a328b97 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -24,6 +26,29 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + FlutterSceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -41,9 +66,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/lib/core/routes/app_routes.dart b/lib/core/routes/app_routes.dart index f8aa9e6..4b039fe 100644 --- a/lib/core/routes/app_routes.dart +++ b/lib/core/routes/app_routes.dart @@ -250,11 +250,14 @@ class FinalCompletionOfDocumentsRouteData extends GoRouteData @TypedGoRoute(path: '/completion_of_documents') class CompletionOfDocumentsRouteData extends GoRouteData with _$CompletionOfDocumentsRouteData { - const CompletionOfDocumentsRouteData(); + final String? tenderId; + const CompletionOfDocumentsRouteData({this.tenderId}); @override Widget build(BuildContext context, GoRouterState state) { - return const CompletionOfDocumentsScreen(); + return tenderDetailProvider( + child: CompletionOfDocumentsScreen(tenderId: tenderId), + ); } } diff --git a/lib/core/routes/app_routes.g.dart b/lib/core/routes/app_routes.g.dart index 261a276..d4e96d6 100644 --- a/lib/core/routes/app_routes.g.dart +++ b/lib/core/routes/app_routes.g.dart @@ -308,10 +308,20 @@ RouteBase get $completionOfDocumentsRouteData => GoRouteData.$route( mixin _$CompletionOfDocumentsRouteData on GoRouteData { static CompletionOfDocumentsRouteData _fromState(GoRouterState state) => - const CompletionOfDocumentsRouteData(); + CompletionOfDocumentsRouteData( + tenderId: state.uri.queryParameters['tender-id'], + ); + + CompletionOfDocumentsRouteData get _self => + this as CompletionOfDocumentsRouteData; @override - String get location => GoRouteData.$location('/completion_of_documents'); + String get location => GoRouteData.$location( + '/completion_of_documents', + queryParams: { + if (_self.tenderId != null) 'tender-id': _self.tenderId!, + }, + ); @override void go(BuildContext context) => context.go(location); diff --git a/lib/view_models/tender_detail_view_model.dart b/lib/view_models/tender_detail_view_model.dart index d5b0b0d..a4c5f99 100644 --- a/lib/view_models/tender_detail_view_model.dart +++ b/lib/view_models/tender_detail_view_model.dart @@ -6,6 +6,7 @@ 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 '../core/constants/tender_approval_status.dart'; +import '../core/constants/tender_submision_mode.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'; @@ -143,4 +144,33 @@ class TenderDetailViewModel with ChangeNotifier { _errorMessage = null; notifyListeners(); } + + /// Submits the tender for completion via the self-apply flow. + /// POSTs to /api/v1/tender-approvals with status "submitted" and + /// submission_mode "self-apply". Returns true on success. + Future submitForCompletion({required String tenderId}) async { + _isSubmitApprovalLoading = true; + _errorMessage = null; + notifyListeners(); + + bool success = false; + final result = await _tendersRepository.toggleApprovals( + tenderId: tenderId, + status: TenderApprovalStatus.submitted.value, + submissionMode: TenderSubmissionMode.selfApply.value, + ); + switch (result) { + case Ok(): + success = true; + _status = result.value.data?.status ?? ''; + break; + case Error(): + _errorMessage = result.error.toString(); + break; + } + + _isSubmitApprovalLoading = false; + notifyListeners(); + return success; + } } diff --git a/lib/view_models/your_tenders_view_model.dart b/lib/view_models/your_tenders_view_model.dart index a7aee20..493b373 100644 --- a/lib/view_models/your_tenders_view_model.dart +++ b/lib/view_models/your_tenders_view_model.dart @@ -206,7 +206,9 @@ class YourTendersViewModel with ChangeNotifier { offset: _tendersOffset, ); await getTenders(requestModel: requestModel); - } else if (selectedStatus == YourTendersStrings.tendersSubmitted) { + } else if (selectedStatus == YourTendersStrings.tendersSubmitted || + selectedStatus == TenderApprovalStatus.submitted.value || + selectedStatus == TenderApprovalStatus.approved.value) { final requestModel = GetTendersRequestModel( status: TenderApprovalStatus.submitted.value, createdFrom: startDateUnix, @@ -299,10 +301,17 @@ class YourTendersViewModel with ChangeNotifier { reset: true, ); } else if (selectedStatus == TenderApprovalStatus.approved.value) { - await getTendersFeedback( - feedbackType: TenderApprovalStatus.approved.value, - reset: true, + // "Approved tenders" maps to submitted tender-approvals. The API has no + // `approved` value; approved tenders are the ones a company has submitted + // for pursuit (GET /api/v1/tender-approvals?status=submitted). + final requestModel = GetTendersRequestModel( + status: TenderApprovalStatus.submitted.value, + createdFrom: startDateUnix, + createdTo: endDateUnix, + limit: _tendersLimit, + offset: _tendersOffset, ); + await getTenders(requestModel: requestModel, reset: true); } } diff --git a/lib/views/completion_of_documents/pages/complectopn_of_documents_screen.dart b/lib/views/completion_of_documents/pages/complectopn_of_documents_screen.dart index 2b902ee..b65d93e 100644 --- a/lib/views/completion_of_documents/pages/complectopn_of_documents_screen.dart +++ b/lib/views/completion_of_documents/pages/complectopn_of_documents_screen.dart @@ -7,7 +7,8 @@ import '../../../core/utils/size_config.dart'; import '../../shared/responsive_builder.dart'; class CompletionOfDocumentsScreen extends StatefulWidget { - const CompletionOfDocumentsScreen({super.key}); + final String? tenderId; + const CompletionOfDocumentsScreen({this.tenderId, super.key}); @override State createState() => _CompletionOfDocumentsScreenState(); @@ -41,10 +42,10 @@ class _CompletionOfDocumentsScreenState extends State( + builder: (context, viewModel, _) => BaseButton( + isEnabled: !viewModel.isSubmitApprovalLoading, + isLoading: viewModel.isSubmitApprovalLoading, + onPressed: () => _submitForCompletion(context), + text: + CompletionOfDocumentsStrings + .submitForCompletion, + textColor: AppColors.textBlue, + backgroundColor: AppColors.primary30, + ), ), SizedBox(height: 24.0.h()), ], @@ -304,6 +312,26 @@ class CompletionOfDocumentsDesktopPage extends StatelessWidget { ); } + Future _submitForCompletion(BuildContext context) async { + final id = tenderId; + if (id == null || id.isEmpty) { + AppToast.error(context, CompletionOfDocumentsStrings.submitError); + return; + } + final viewModel = context.read(); + final success = await viewModel.submitForCompletion(tenderId: id); + if (!context.mounted) return; + if (success) { + AppToast.success(context, CompletionOfDocumentsStrings.submitSuccess); + context.pop(); + } else { + AppToast.error( + context, + viewModel.errorMessage ?? CompletionOfDocumentsStrings.submitError, + ); + } + } + Widget _docCard({ required String title, required String subtitle, diff --git a/lib/views/completion_of_documents/pages/m_completion_of_documents_page.dart b/lib/views/completion_of_documents/pages/m_completion_of_documents_page.dart index 22bcbd2..0d28c32 100644 --- a/lib/views/completion_of_documents/pages/m_completion_of_documents_page.dart +++ b/lib/views/completion_of_documents/pages/m_completion_of_documents_page.dart @@ -3,13 +3,18 @@ import 'package:flutter_svg/svg.dart'; import 'package:tm_app/core/constants/assets.dart'; import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.dart'; +import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; +import 'package:tm_app/core/utils/app_toast.dart'; +import 'package:tm_app/view_models/tender_detail_view_model.dart'; import 'package:tm_app/views/completion_of_documents/strings/completion_of_documents_string.dart'; import 'package:tm_app/views/shared/base_button.dart'; import '../../shared/tender_app_bar.dart'; class CompletionOfDocumentsMobilePage extends StatelessWidget { - const CompletionOfDocumentsMobilePage({super.key}); + final String? tenderId; + const CompletionOfDocumentsMobilePage({this.tenderId, super.key}); @override Widget build(BuildContext context) { @@ -242,12 +247,15 @@ class CompletionOfDocumentsMobilePage extends StatelessWidget { ), ), SizedBox(height: 24.0.h()), - BaseButton( - isEnabled: true, - onPressed: () {}, - text: CompletionOfDocumentsStrings.submitForCompletion, - textColor: AppColors.textBlue, - backgroundColor: AppColors.primary30, + Consumer( + builder: (context, viewModel, _) => BaseButton( + isEnabled: !viewModel.isSubmitApprovalLoading, + isLoading: viewModel.isSubmitApprovalLoading, + onPressed: () => _submitForCompletion(context), + text: CompletionOfDocumentsStrings.submitForCompletion, + textColor: AppColors.textBlue, + backgroundColor: AppColors.primary30, + ), ), ], ), @@ -256,6 +264,26 @@ class CompletionOfDocumentsMobilePage extends StatelessWidget { ); } + Future _submitForCompletion(BuildContext context) async { + final id = tenderId; + if (id == null || id.isEmpty) { + AppToast.error(context, CompletionOfDocumentsStrings.submitError); + return; + } + final viewModel = context.read(); + final success = await viewModel.submitForCompletion(tenderId: id); + if (!context.mounted) return; + if (success) { + AppToast.success(context, CompletionOfDocumentsStrings.submitSuccess); + context.pop(); + } else { + AppToast.error( + context, + viewModel.errorMessage ?? CompletionOfDocumentsStrings.submitError, + ); + } + } + Widget _docCard({ required String title, required String subtitle, diff --git a/lib/views/completion_of_documents/pages/t_completion_of_documents_page.dart b/lib/views/completion_of_documents/pages/t_completion_of_documents_page.dart index adbeeff..de5a21b 100644 --- a/lib/views/completion_of_documents/pages/t_completion_of_documents_page.dart +++ b/lib/views/completion_of_documents/pages/t_completion_of_documents_page.dart @@ -3,6 +3,10 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:tm_app/core/constants/assets.dart'; import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.dart'; +import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; +import 'package:tm_app/core/utils/app_toast.dart'; +import 'package:tm_app/view_models/tender_detail_view_model.dart'; import 'package:tm_app/views/completion_of_documents/strings/completion_of_documents_string.dart'; import 'package:tm_app/views/shared/base_button.dart'; import 'package:tm_app/views/shared/tablet_desktop_appbar.dart'; @@ -10,7 +14,8 @@ import 'package:tm_app/views/shared/tablet_navigation_widget.dart'; import 'package:tm_app/views/shared/tender_app_bar.dart'; class CompletionOfDocumentsTabletPage extends StatelessWidget { - const CompletionOfDocumentsTabletPage({super.key}); + final String? tenderId; + const CompletionOfDocumentsTabletPage({this.tenderId, super.key}); @override Widget build(BuildContext context) { @@ -83,14 +88,17 @@ class CompletionOfDocumentsTabletPage extends StatelessWidget { SizedBox(height: 24.0.h()), - BaseButton( - isEnabled: true, - onPressed: () {}, - text: - CompletionOfDocumentsStrings - .submitForCompletion, - textColor: AppColors.textBlue, - backgroundColor: AppColors.primary30, + Consumer( + builder: (context, viewModel, _) => BaseButton( + isEnabled: !viewModel.isSubmitApprovalLoading, + isLoading: viewModel.isSubmitApprovalLoading, + onPressed: () => _submitForCompletion(context), + text: + CompletionOfDocumentsStrings + .submitForCompletion, + textColor: AppColors.textBlue, + backgroundColor: AppColors.primary30, + ), ), ], ), @@ -309,6 +317,26 @@ class CompletionOfDocumentsTabletPage extends StatelessWidget { ); } + Future _submitForCompletion(BuildContext context) async { + final id = tenderId; + if (id == null || id.isEmpty) { + AppToast.error(context, CompletionOfDocumentsStrings.submitError); + return; + } + final viewModel = context.read(); + final success = await viewModel.submitForCompletion(tenderId: id); + if (!context.mounted) return; + if (success) { + AppToast.success(context, CompletionOfDocumentsStrings.submitSuccess); + context.pop(); + } else { + AppToast.error( + context, + viewModel.errorMessage ?? CompletionOfDocumentsStrings.submitError, + ); + } + } + // -------------------- Document Card -------------------- Widget _docCard({ required String title, diff --git a/lib/views/completion_of_documents/strings/completion_of_documents_string.dart b/lib/views/completion_of_documents/strings/completion_of_documents_string.dart index 14af095..c2baa04 100644 --- a/lib/views/completion_of_documents/strings/completion_of_documents_string.dart +++ b/lib/views/completion_of_documents/strings/completion_of_documents_string.dart @@ -7,4 +7,6 @@ class CompletionOfDocumentsStrings { 'Set Deadline for Completion of documents :'; static const String note = 'Note:'; static const String submitForCompletion = 'Submit for completion'; + static const String submitSuccess = 'Tender submitted for completion'; + static const String submitError = 'Failed to submit tender for completion'; } diff --git a/lib/views/detail/widgets/tender_detail_action.dart b/lib/views/detail/widgets/tender_detail_action.dart index e2a8e08..4dac05c 100644 --- a/lib/views/detail/widgets/tender_detail_action.dart +++ b/lib/views/detail/widgets/tender_detail_action.dart @@ -75,9 +75,9 @@ class _TenderDetailActionsState extends State { // submissionMode: value, // ); - const CompletionOfDocumentsRouteData().push( - context, - ); + CompletionOfDocumentsRouteData( + tenderId: widget.detail.id!, + ).push(context); } else if (value == TenderSubmissionMode.partnership.value) { Future.delayed(Duration.zero, () { @@ -213,8 +213,9 @@ class _TenderDetailActionsState extends State { const FinalCompletionOfDocumentsRouteData() .push(context); } else { - const CompletionOfDocumentsRouteData() - .push(context); + CompletionOfDocumentsRouteData( + tenderId: widget.detail.id!, + ).push(context); } } } else if (value == diff --git a/lib/views/profile/strings/profile_strings.dart b/lib/views/profile/strings/profile_strings.dart index ab08801..f19f769 100644 --- a/lib/views/profile/strings/profile_strings.dart +++ b/lib/views/profile/strings/profile_strings.dart @@ -23,4 +23,5 @@ class ProfileStrings { static const String mainDataTab = 'Main Data'; static const String membersTab = 'Members'; static const String subjectTab = 'Subject'; + static const String appVersion = 'Version 1.0.7'; } diff --git a/lib/views/profile/widgets/main_data_tab.dart b/lib/views/profile/widgets/main_data_tab.dart index 9171a59..c176ada 100644 --- a/lib/views/profile/widgets/main_data_tab.dart +++ b/lib/views/profile/widgets/main_data_tab.dart @@ -98,6 +98,15 @@ class MainDataTab extends StatelessWidget { ), ), ), + SizedBox(height: 24.0.h()), + Text( + ProfileStrings.appVersion, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey70, + ), + ), ], ), );