From be6b0bbe987136a4f08be2ccb1746bc70c720275 Mon Sep 17 00:00:00 2001 From: llsajjad Date: Mon, 13 Oct 2025 11:54:23 +0330 Subject: [PATCH 1/2] added web tablet pages --- lib/core/config/dependencies.dart | 6 + lib/core/constants/common_strings.dart | 1 + lib/core/routes/app_routes.dart | 15 + lib/core/routes/app_routes.g.dart | 28 ++ .../complectopn_of_documents_screen.dart | 50 +++ .../pages/d_completion_of_documents_page.dart | 390 ++++++++++++++++++ .../pages/m_completion_of_documents_page.dart | 29 +- .../pages/t_completion_of_documents_page.dart | 385 +++++++++++++++++ .../select_meeting_time_bottom_sheet.dart | 5 +- ...show_select_meeting_time_bottom_sheet.dart | 29 ++ .../detail/widgets/tender_detail_action.dart | 76 +++- ...op_final_completion_of_documents_page.dart | 326 +++++++++++++++ .../final_completion_of_documents_screen.dart | 346 ++-------------- ...le_final_completion_of_documents_page.dart | 314 ++++++++++++++ ...et_final_completion_of_documents_page.dart | 343 +++++++++++++++ .../shared/select_submission_dialog.dart | 71 +++- 16 files changed, 2059 insertions(+), 355 deletions(-) create mode 100644 lib/views/completion_of_documents/pages/complectopn_of_documents_screen.dart create mode 100644 lib/views/completion_of_documents/pages/d_completion_of_documents_page.dart create mode 100644 lib/views/completion_of_documents/pages/t_completion_of_documents_page.dart create mode 100644 lib/views/detail/widgets/show_select_meeting_time_bottom_sheet.dart create mode 100644 lib/views/final_completion_of_documents/pages/desktop_final_completion_of_documents_page.dart create mode 100644 lib/views/final_completion_of_documents/pages/mobile_final_completion_of_documents_page.dart create mode 100644 lib/views/final_completion_of_documents/pages/tablet_final_completion_of_documents_page.dart diff --git a/lib/core/config/dependencies.dart b/lib/core/config/dependencies.dart index b1b3497..01a1e53 100644 --- a/lib/core/config/dependencies.dart +++ b/lib/core/config/dependencies.dart @@ -16,6 +16,7 @@ import 'package:tm_app/data/services/notification_service.dart'; import 'package:tm_app/data/services/notification_state_service.dart'; import 'package:tm_app/data/services/tender_detail_service.dart'; import 'package:tm_app/data/services/your_tenders_service.dart'; +import 'package:tm_app/view_models/final_completion_of_documents_view_model.dart'; import '../../data/repositories/auth_repository.dart'; import '../../data/repositories/profile_repository.dart'; @@ -158,6 +159,11 @@ List get authProvider { ChangeNotifierProvider( create: (context) => AuthViewModel(authRepository: context.read()), lazy: false, // Load immediately for auth state checks + ), + + ChangeNotifierProvider( + create: (context) => FinalCompletionOfDocumentsViewModel(), + lazy: false, // Load immediately for auth state checks ), ]; } diff --git a/lib/core/constants/common_strings.dart b/lib/core/constants/common_strings.dart index cdfd6b4..0e5e488 100644 --- a/lib/core/constants/common_strings.dart +++ b/lib/core/constants/common_strings.dart @@ -7,4 +7,5 @@ class CommonStrings { static const String selfApply = 'Self-apply'; static const String partnership = 'Partnership'; static const String confirm = 'Confirm'; + static const String cancel = 'Cancel'; } diff --git a/lib/core/routes/app_routes.dart b/lib/core/routes/app_routes.dart index b1dae20..e7bc7ab 100644 --- a/lib/core/routes/app_routes.dart +++ b/lib/core/routes/app_routes.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:tm_app/views/completion_of_documents/pages/complectopn_of_documents_screen.dart'; import 'package:tm_app/views/completion_of_documents/pages/m_completion_of_documents_page.dart'; import 'package:tm_app/views/detail/pages/detail_screen.dart'; import 'package:tm_app/views/forget_password_create/pages/forgot_password_create_screen.dart'; @@ -235,6 +236,20 @@ class FinalCompletionOfDocumentsRouteData extends GoRouteData } } +@TypedGoRoute( + path: '/completion_of_documents', +) +class CompletionOfDocumentsRouteData extends GoRouteData + with _$CompletionOfDocumentsRouteData { + const CompletionOfDocumentsRouteData(); + + @override + Widget build(BuildContext context, GoRouterState state) { + return const CompletionOfDocumentsScreen(); + + } +} + @TypedGoRoute(path: '/like-tenders') class LikedTendersRouteData extends GoRouteData with _$LikedTendersRouteData { const LikedTendersRouteData(); diff --git a/lib/core/routes/app_routes.g.dart b/lib/core/routes/app_routes.g.dart index 2000a07..6c2b7b6 100644 --- a/lib/core/routes/app_routes.g.dart +++ b/lib/core/routes/app_routes.g.dart @@ -12,6 +12,7 @@ List get $appRoutes => [ $appShellRouteData, $yourTendersRouteData, $finalCompletionOfDocumentsRouteData, + $completionOfDocumentsRouteData, $likedTendersRouteData, $completionOfDocumentsMobileRouteData, $tenderDetailRouteData, @@ -294,6 +295,33 @@ mixin _$FinalCompletionOfDocumentsRouteData on GoRouteData { void replace(BuildContext context) => context.replace(location); } +RouteBase get $completionOfDocumentsRouteData => GoRouteData.$route( + path: '/completion_of_documents', + + factory: _$CompletionOfDocumentsRouteData._fromState, +); + +mixin _$CompletionOfDocumentsRouteData on GoRouteData { + static CompletionOfDocumentsRouteData _fromState(GoRouterState state) => + const CompletionOfDocumentsRouteData(); + + @override + String get location => GoRouteData.$location('/completion_of_documents'); + + @override + void go(BuildContext context) => context.go(location); + + @override + Future push(BuildContext context) => context.push(location); + + @override + void pushReplacement(BuildContext context) => + context.pushReplacement(location); + + @override + void replace(BuildContext context) => context.replace(location); +} + RouteBase get $likedTendersRouteData => GoRouteData.$route( path: '/like-tenders', 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 new file mode 100644 index 0000000..2b902ee --- /dev/null +++ b/lib/views/completion_of_documents/pages/complectopn_of_documents_screen.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/views/completion_of_documents/pages/d_completion_of_documents_page.dart'; +import 'package:tm_app/views/completion_of_documents/pages/m_completion_of_documents_page.dart'; +import 'package:tm_app/views/completion_of_documents/pages/t_completion_of_documents_page.dart'; + +import '../../../core/utils/size_config.dart'; +import '../../shared/responsive_builder.dart'; + +class CompletionOfDocumentsScreen extends StatefulWidget { + const CompletionOfDocumentsScreen({super.key}); + + @override + State createState() => _CompletionOfDocumentsScreenState(); +} + +class _CompletionOfDocumentsScreenState extends State { + // late final HomeViewModel _viewModel; + // late final TabNavigationService _tabService; + + @override + void initState() { + super.initState(); + // _viewModel = context.read(); + // _tabService = context.read(); + // _tabService.addListener(_onTabChanged); + } + + @override + void dispose() { + // _tabService.removeListener(_onTabChanged); + super.dispose(); + } + + // void _onTabChanged() { + // // Tab index 0 is Home + // if (_tabService.currentTabIndex == 0 && mounted) { + // _viewModel.init(); + // } + // } + + @override + Widget build(BuildContext context) { + SizeConfig.init(context); + return const ResponsiveBuilder( + mobile: CompletionOfDocumentsMobilePage(), + tablet: CompletionOfDocumentsTabletPage(), + desktop: CompletionOfDocumentsDesktopPage(), + ); + } +} diff --git a/lib/views/completion_of_documents/pages/d_completion_of_documents_page.dart b/lib/views/completion_of_documents/pages/d_completion_of_documents_page.dart new file mode 100644 index 0000000..bd97161 --- /dev/null +++ b/lib/views/completion_of_documents/pages/d_completion_of_documents_page.dart @@ -0,0 +1,390 @@ +import 'package:flutter/material.dart'; +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: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/desktop_navigation_widget.dart'; + +class CompletionOfDocumentsDesktopPage extends StatelessWidget { + const CompletionOfDocumentsDesktopPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.backgroundColor, + body: Column( + children: [ + const DesktopNavigationWidget(currentIndex: 0), + SizedBox( + width: 760, + child: SingleChildScrollView( + child: Center( + child: SizedBox( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 24.0.h()), + child: Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + SvgPicture.asset( + AssetsManager.arrowLeft, + width: 24.0.w(), + height: 24.0.h(), + ), + SizedBox(width: 8.0.w()), + Text( + CompletionOfDocumentsStrings + .completionOfDocuments, + style: TextStyle( + color: AppColors.grey70, + fontSize: 16.0.sp(), + fontWeight: FontWeight.w600, + ), + ), + ], + ), + SizedBox(height: 24.0.h()), + + _deadlineContainer(), + + SizedBox(height: 16.0.h()), + + _matchProfileProgress(), + + SizedBox(height: 24.0.h()), + + _docCardsSection(), + + SizedBox(height: 24.0.h()), + + _deadlinePicker(), + + SizedBox(height: 16.0.h()), + + _noteField(), + + SizedBox(height: 24.0.h()), + + BaseButton( + isEnabled: true, + onPressed: () {}, + text: + CompletionOfDocumentsStrings + .submitForCompletion, + textColor: AppColors.textBlue, + backgroundColor: AppColors.primary30, + ), + ], + ), + ), + ), + ), + ), + ), + ), + ], + ), + ); + } + + Widget _deadlineContainer() { + return Container( + width: double.infinity, + height: 24.0.h(), + padding: EdgeInsets.symmetric(horizontal: 8.0.w()), + decoration: BoxDecoration( + color: AppColors.primary20, + borderRadius: BorderRadius.circular(4), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + CompletionOfDocumentsStrings.submissionDeadline, + style: TextStyle( + color: AppColors.textBlue, + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + ), + ), + Text( + '2025-06-15', + style: TextStyle( + color: AppColors.grey80, + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ); + } + + Widget _matchProfileProgress() { + return Container( + height: 58.0.h(), + width: double.infinity, + padding: EdgeInsets.symmetric(horizontal: 12.0.w(), vertical: 8.0.h()), + decoration: BoxDecoration( + border: Border.all(color: AppColors.orange10), + borderRadius: BorderRadius.circular(8), + color: AppColors.orange0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + 'Match with your profile', + style: TextStyle( + fontSize: 12.0.sp(), + color: AppColors.grey80, + fontWeight: FontWeight.w400, + ), + ), + const Spacer(), + Text( + '75%', + style: TextStyle( + fontSize: 12.0.sp(), + color: AppColors.cyanTeal, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + SizedBox(height: 4.0.h()), + LinearProgressIndicator( + value: 0.75, + backgroundColor: const Color(0xFFE0E0E0), + color: AppColors.cyanTeal, + minHeight: 6, + borderRadius: BorderRadius.circular(10), + ), + ], + ), + ); + } + + Widget _docCardsSection() { + return Column( + children: [ + _docCard( + title: 'Company Registration Certificate', + subtitle: 'Legal document proving business registration', + status: 'Completed', + statusColor: AppColors.green30, + statusBackgroundColor: AppColors.green10, + backgroundColor: AppColors.primary10Light, + borderSideColor: AppColors.primary30, + ), + _docCard( + title: 'Tax Compliance Certificate', + subtitle: 'Proof of tax registration and compliance', + status: 'Completed', + statusColor: AppColors.green30, + statusBackgroundColor: AppColors.green10, + backgroundColor: AppColors.primary10Light, + borderSideColor: AppColors.primary30, + ), + _docCard( + title: 'Technical Proposal', + subtitle: 'Detailed technical solution for the tender', + status: 'Incomplete', + statusColor: AppColors.red20, + statusBackgroundColor: AppColors.red10, + backgroundColor: AppColors.red0, + tag: 'Self apply', + tagColor: AppColors.green30, + borderSideColor: AppColors.red10, + tagBackgroundColor: AppColors.green20, + ), + _docCard( + title: 'Financial Proposal', + subtitle: 'Detailed cost breakdown and pricing', + status: 'Incomplete', + statusColor: AppColors.red20, + statusBackgroundColor: AppColors.red10, + backgroundColor: AppColors.red0, + tag: 'Partnership', + tagColor: AppColors.purple, + borderSideColor: AppColors.red10, + tagBackgroundColor: AppColors.purpleLight, + ), + _docCard( + title: 'Financial Proposal', + subtitle: 'Detailed cost breakdown and pricing', + status: 'Incomplete', + statusColor: AppColors.red20, + statusBackgroundColor: AppColors.red10, + backgroundColor: AppColors.red0, + borderSideColor: AppColors.red10, + ), + ], + ); + } + + Widget _deadlinePicker() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + CompletionOfDocumentsStrings.setDeadline, + style: TextStyle( + fontSize: 16.0.sp(), + color: AppColors.grey80, + fontWeight: FontWeight.w600, + ), + ), + SizedBox(height: 8.0.h()), + Container( + height: 48.0.h(), + padding: EdgeInsets.symmetric(horizontal: 12.0.w()), + decoration: BoxDecoration( + border: Border.all(color: AppColors.grey40), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '2025/04/10', + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w700, + color: AppColors.grey60, + ), + ), + SvgPicture.asset( + AssetsManager.calendar, + height: 24.0.h(), + width: 24.0.w(), + ), + ], + ), + ), + ], + ); + } + + Widget _noteField() { + return Container( + padding: const EdgeInsets.all(12), + height: 100.0.h(), + decoration: BoxDecoration( + border: Border.all(color: AppColors.borderColor), + borderRadius: BorderRadius.circular(8), + color: AppColors.grey0, + ), + child: TextField( + maxLines: null, + decoration: const InputDecoration.collapsed( + hintText: CompletionOfDocumentsStrings.note, + ), + style: TextStyle( + fontSize: 16.0.sp(), + color: AppColors.grey60, + fontWeight: FontWeight.w400, + ), + ), + ); + } + + Widget _docCard({ + required String title, + required String subtitle, + required String status, + required Color statusColor, + required Color backgroundColor, + required Color borderSideColor, + required Color statusBackgroundColor, + String? tag, + Color? tagColor, + Color? tagBackgroundColor, + }) { + return Container( + width: double.infinity, + margin: EdgeInsets.only(bottom: 12.0.h()), + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: backgroundColor, + border: Border( + left: BorderSide(color: borderSideColor, width: 2.0.w()), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + if (tag != null) ...[ + const Spacer(), + Container( + margin: const EdgeInsets.only(right: 8), + height: 32.0.h(), + width: 91.0.w(), + decoration: BoxDecoration( + color: tagBackgroundColor, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Text( + tag, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w500, + color: tagColor, + ), + ), + ), + ), + ] else + const Spacer(), + Container( + height: 32.0.h(), + width: 91.0.w(), + decoration: BoxDecoration( + color: statusBackgroundColor, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Text( + status, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w500, + color: statusColor, + ), + ), + ), + ), + ], + ), + SizedBox(height: 8.0.h()), + Text( + title, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey70, + ), + ), + SizedBox(height: 4.0.h()), + Text( + subtitle, + style: TextStyle( + fontSize: 16.0.sp(), + color: AppColors.grey, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ); + } +} 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 3eaf6ba..f7db376 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 @@ -5,7 +5,6 @@ import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.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/tender_app_bar.dart'; class CompletionOfDocumentsMobilePage extends StatelessWidget { const CompletionOfDocumentsMobilePage({super.key}); @@ -14,10 +13,10 @@ class CompletionOfDocumentsMobilePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.backgroundColor, - appBar: appBar( - context: context, - title: CompletionOfDocumentsStrings.completionOfDocuments, - ), + // appBar: appBar( + // context: context, + // title: CompletionOfDocumentsStrings.completionOfDocuments, + // ), body: SafeArea( child: SingleChildScrollView( padding: EdgeInsets.symmetric( @@ -27,6 +26,26 @@ class CompletionOfDocumentsMobilePage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Row( + children: [ + SvgPicture.asset( + AssetsManager.arrowLeft, + width: 24.0.w(), + height: 24.0.h(), + ), + SizedBox(width: 8.0.w()), + Text( + CompletionOfDocumentsStrings.completionOfDocuments, + style: TextStyle( + color: AppColors.grey70, + fontSize: 16.0.sp(), + fontWeight: FontWeight.w600, + ), + ), + ], + ), + SizedBox(height: 24.0.h()), + Container( width: double.infinity, height: 24.0.h(), 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 new file mode 100644 index 0000000..54f34ac --- /dev/null +++ b/lib/views/completion_of_documents/pages/t_completion_of_documents_page.dart @@ -0,0 +1,385 @@ +import 'package:flutter/material.dart'; +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: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'; +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}); + + @override + Widget build(BuildContext context) { + final GlobalKey key = GlobalKey(); + return Scaffold( + key: key, + backgroundColor: AppColors.backgroundColor, + appBar: tabletAppBar( + title: CompletionOfDocumentsStrings.completionOfDocuments, + key: key, + context: context, + ), + drawer: const TabletNavigationWidget(currentIndex: 0), + body: SafeArea( + child: Center( + child: SizedBox( + width: 720, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const TabletDesktopAppbar( + title: CompletionOfDocumentsStrings.completionOfDocuments, + haveFilter: false, + ), + + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 24.0.h()), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _deadlineContainer(), + + SizedBox(height: 16.0.h()), + + _matchProfileProgress(), + + SizedBox(height: 24.0.h()), + + _docCardsSection(), + + SizedBox(height: 24.0.h()), + + _deadlinePicker(), + + SizedBox(height: 16.0.h()), + + _noteField(), + + SizedBox(height: 24.0.h()), + + BaseButton( + isEnabled: true, + onPressed: () {}, + text: + CompletionOfDocumentsStrings + .submitForCompletion, + textColor: AppColors.textBlue, + backgroundColor: AppColors.primary30, + ), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ), + ); + } + + Widget _deadlineContainer() { + return Container( + width: double.infinity, + height: 24.0.h(), + padding: EdgeInsets.symmetric(horizontal: 8.0.w()), + decoration: BoxDecoration( + color: AppColors.primary20, + borderRadius: BorderRadius.circular(4), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + CompletionOfDocumentsStrings.submissionDeadline, + style: TextStyle( + color: AppColors.textBlue, + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + ), + ), + Text( + '2025-06-15', + style: TextStyle( + color: AppColors.grey80, + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ); + } + + Widget _matchProfileProgress() { + return Container( + height: 58.0.h(), + width: double.infinity, + padding: EdgeInsets.symmetric(horizontal: 12.0.w(), vertical: 8.0.h()), + decoration: BoxDecoration( + border: Border.all(color: AppColors.orange10), + borderRadius: BorderRadius.circular(8), + color: AppColors.orange0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + 'Match with your profile', + style: TextStyle( + fontSize: 12.0.sp(), + color: AppColors.grey80, + fontWeight: FontWeight.w400, + ), + ), + const Spacer(), + Text( + '75%', + style: TextStyle( + fontSize: 12.0.sp(), + color: AppColors.cyanTeal, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + SizedBox(height: 4.0.h()), + LinearProgressIndicator( + value: 0.75, + backgroundColor: const Color(0xFFE0E0E0), + color: AppColors.cyanTeal, + minHeight: 6, + borderRadius: BorderRadius.circular(10), + ), + ], + ), + ); + } + + Widget _docCardsSection() { + return Column( + children: [ + _docCard( + title: 'Company Registration Certificate', + subtitle: 'Legal document proving business registration', + status: 'Completed', + statusColor: AppColors.green30, + statusBackgroundColor: AppColors.green10, + backgroundColor: AppColors.primary10Light, + borderSideColor: AppColors.primary30, + ), + _docCard( + title: 'Tax Compliance Certificate', + subtitle: 'Proof of tax registration and compliance', + status: 'Completed', + statusColor: AppColors.green30, + statusBackgroundColor: AppColors.green10, + backgroundColor: AppColors.primary10Light, + borderSideColor: AppColors.primary30, + ), + _docCard( + title: 'Technical Proposal', + subtitle: 'Detailed technical solution for the tender', + status: 'Incomplete', + statusColor: AppColors.red20, + statusBackgroundColor: AppColors.red10, + backgroundColor: AppColors.red0, + tag: 'Self apply', + tagColor: AppColors.green30, + borderSideColor: AppColors.red10, + tagBackgroundColor: AppColors.green20, + ), + _docCard( + title: 'Financial Proposal', + subtitle: 'Detailed cost breakdown and pricing', + status: 'Incomplete', + statusColor: AppColors.red20, + statusBackgroundColor: AppColors.red10, + backgroundColor: AppColors.red0, + tag: 'Partnership', + tagColor: AppColors.purple, + borderSideColor: AppColors.red10, + tagBackgroundColor: AppColors.purpleLight, + ), + _docCard( + title: 'Financial Proposal', + subtitle: 'Detailed cost breakdown and pricing', + status: 'Incomplete', + statusColor: AppColors.red20, + statusBackgroundColor: AppColors.red10, + backgroundColor: AppColors.red0, + borderSideColor: AppColors.red10, + ), + ], + ); + } + + Widget _deadlinePicker() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + CompletionOfDocumentsStrings.setDeadline, + style: TextStyle( + fontSize: 16.0.sp(), + color: AppColors.grey80, + fontWeight: FontWeight.w600, + ), + ), + SizedBox(height: 8.0.h()), + Container( + height: 48.0.h(), + padding: EdgeInsets.symmetric(horizontal: 12.0.w()), + decoration: BoxDecoration( + border: Border.all(color: AppColors.grey40), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '2025/04/10', + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w700, + color: AppColors.grey60, + ), + ), + SvgPicture.asset( + AssetsManager.calendar, + height: 24.0.h(), + width: 24.0.w(), + ), + ], + ), + ), + ], + ); + } + + Widget _noteField() { + return Container( + padding: const EdgeInsets.all(12), + height: 100.0.h(), + decoration: BoxDecoration( + border: Border.all(color: AppColors.borderColor), + borderRadius: BorderRadius.circular(8), + color: AppColors.grey0, + ), + child: TextField( + maxLines: null, + decoration: const InputDecoration.collapsed( + hintText: CompletionOfDocumentsStrings.note, + ), + style: TextStyle( + fontSize: 16.0.sp(), + color: AppColors.grey60, + fontWeight: FontWeight.w400, + ), + ), + ); + } + + // -------------------- Document Card -------------------- + Widget _docCard({ + required String title, + required String subtitle, + required String status, + required Color statusColor, + required Color backgroundColor, + required Color borderSideColor, + required Color statusBackgroundColor, + String? tag, + Color? tagColor, + Color? tagBackgroundColor, + }) { + return Container( + width: double.infinity, + margin: EdgeInsets.only(bottom: 12.0.h()), + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: backgroundColor, + border: Border( + left: BorderSide(color: borderSideColor, width: 2.0.w()), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + if (tag != null) ...[ + const Spacer(), + Container( + margin: const EdgeInsets.only(right: 8), + height: 32.0.h(), + width: 91.0.w(), + decoration: BoxDecoration( + color: tagBackgroundColor, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Text( + tag, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w500, + color: tagColor, + ), + ), + ), + ), + ] else + const Spacer(), + Container( + height: 32.0.h(), + width: 91.0.w(), + decoration: BoxDecoration( + color: statusBackgroundColor, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Text( + status, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w500, + color: statusColor, + ), + ), + ), + ), + ], + ), + SizedBox(height: 8.0.h()), + Text( + title, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey70, + ), + ), + SizedBox(height: 4.0.h()), + Text( + subtitle, + style: TextStyle( + fontSize: 16.0.sp(), + color: AppColors.grey, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ); + } +} diff --git a/lib/views/detail/widgets/select_meeting_time_bottom_sheet.dart b/lib/views/detail/widgets/select_meeting_time_bottom_sheet.dart index e5c3394..be383a6 100644 --- a/lib/views/detail/widgets/select_meeting_time_bottom_sheet.dart +++ b/lib/views/detail/widgets/select_meeting_time_bottom_sheet.dart @@ -5,8 +5,9 @@ import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/views/detail/strings/tender_details_strings.dart'; class SelectMeetingTimeBottomSheet extends StatefulWidget { - const SelectMeetingTimeBottomSheet({required this.onConfirm, super.key}); + const SelectMeetingTimeBottomSheet({required this.onConfirm, required this.isDialog, super.key}); final ValueChanged onConfirm; + final bool isDialog; @override State createState() => @@ -35,7 +36,7 @@ class _SelectMeetingTimeBottomSheetState padding: EdgeInsets.fromLTRB(24.0.w(), 24.0.h(), 24.0.w(), 33.0.h()), decoration: BoxDecoration( color: AppColors.backgroundColor, - borderRadius: const BorderRadius.only( + borderRadius: widget.isDialog ? const BorderRadius.all(Radius.circular(16.0)) : const BorderRadius.only( topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0), ), diff --git a/lib/views/detail/widgets/show_select_meeting_time_bottom_sheet.dart b/lib/views/detail/widgets/show_select_meeting_time_bottom_sheet.dart new file mode 100644 index 0000000..3b4dd51 --- /dev/null +++ b/lib/views/detail/widgets/show_select_meeting_time_bottom_sheet.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/views/detail/widgets/select_meeting_time_bottom_sheet.dart'; + +Future showSelectMeetingTimeDialog({ + required BuildContext context, + required ValueChanged onConfirm, +}) async { + await showDialog( + context: context, + barrierDismissible: true, + builder: (dialogContext) { + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + insetPadding: const EdgeInsets.symmetric(horizontal: 32, vertical: 24), + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 500), + child: SelectMeetingTimeBottomSheet( + isDialog: true, + onConfirm: (value) { + onConfirm(value); + }, + ), + ), + ); + }, + ); +} diff --git a/lib/views/detail/widgets/tender_detail_action.dart b/lib/views/detail/widgets/tender_detail_action.dart index 1d04aa8..6cabbbf 100644 --- a/lib/views/detail/widgets/tender_detail_action.dart +++ b/lib/views/detail/widgets/tender_detail_action.dart @@ -4,6 +4,7 @@ import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/view_models/tender_detail_view_model.dart'; import 'package:tm_app/views/detail/widgets/select_meeting_time_bottom_sheet.dart'; +import 'package:tm_app/views/detail/widgets/show_select_meeting_time_bottom_sheet.dart'; import 'package:tm_app/views/shared/base_button.dart'; import 'package:tm_app/views/shared/select_submission_bottom_sheet.dart'; @@ -53,28 +54,28 @@ class TenderDetailActions extends StatelessWidget { onPressed: () { { showModalBottomSheet( - isDismissible: true, context: context, - builder: (bottomSheetContext) { + builder: (context) { return SelectSubmissionBottomSheet( - onConfirm: (value) { - // viewModel.submitTenderApproval( - // tenderId: detail.id!, - // submissionMode: value, - // ); + onConfirm: (String value) { if (value == TenderSubmissionMode.selfApply.value) { - const CompletionOfDocumentsMobileRouteData() - .push(context); - } else { + viewModel.submitTenderApproval( + tenderId: detail.id!, + submissionMode: value, + ); + } else if (value == + TenderSubmissionMode.partnership.value) { Future.delayed(Duration.zero, () { - showModalBottomSheet( - isDismissible: true, - // ignore: use_build_context_synchronously + showDialog( context: context, builder: (context) { return SelectMeetingTimeBottomSheet( - onConfirm: (meetingTime) {}, + onConfirm: (String value) { + const CompletionOfDocumentsRouteData() + .push(context); + }, + isDialog: false, ); }, ); @@ -186,10 +187,24 @@ class TenderDetailActions extends StatelessWidget { builder: (context) { return SelectSubmissionDialog( onConfirm: (String value) { - viewModel.submitTenderApproval( - tenderId: detail.id!, - submissionMode: value, - ); + if (value == + TenderSubmissionMode.selfApply.value) { + const FinalCompletionOfDocumentsRouteData() + .push(context); + } else if (value == + TenderSubmissionMode.partnership.value) { + WidgetsBinding.instance.addPostFrameCallback(( + timeStamp, + ) { + showSelectMeetingTimeDialog( + context: context, + onConfirm: (String value) { + const CompletionOfDocumentsRouteData() + .push(context); + }, + ); + }); + } }, ); }, @@ -199,10 +214,27 @@ class TenderDetailActions extends StatelessWidget { builder: (context) { return SelectSubmissionBottomSheet( onConfirm: (String value) { - viewModel.submitTenderApproval( - tenderId: detail.id!, - submissionMode: value, - ); + if (value == + TenderSubmissionMode.selfApply.value) { + viewModel.submitTenderApproval( + tenderId: detail.id!, + submissionMode: value, + ); + } else if (value == + TenderSubmissionMode.partnership.value) { + showDialog( + context: context, + builder: (context) { + return SelectMeetingTimeBottomSheet( + onConfirm: (String value) { + const CompletionOfDocumentsRouteData() + .push(context); + }, + isDialog: false, + ); + }, + ); + } }, ); }, diff --git a/lib/views/final_completion_of_documents/pages/desktop_final_completion_of_documents_page.dart b/lib/views/final_completion_of_documents/pages/desktop_final_completion_of_documents_page.dart new file mode 100644 index 0000000..01423e5 --- /dev/null +++ b/lib/views/final_completion_of_documents/pages/desktop_final_completion_of_documents_page.dart @@ -0,0 +1,326 @@ +import 'package:dotted_border/dotted_border.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:provider/provider.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:tm_app/view_models/final_completion_of_documents_view_model.dart'; +import 'package:tm_app/views/final_completion_of_documents/strings/final_completion_of_documents_strings.dart'; +import 'package:tm_app/views/final_completion_of_documents/widgets/comment_box.dart'; +import 'package:tm_app/views/login/widgets/widgets.dart'; +import 'package:tm_app/views/shared/desktop_navigation_widget.dart'; +import 'package:tm_app/views/shared/tablet_desktop_appbar.dart'; + +import '../../shared/main_drop_down.dart'; + +class DesktopFinalCompletionOfDocumentsPage extends StatelessWidget { + const DesktopFinalCompletionOfDocumentsPage({super.key}); + + @override + Widget build(BuildContext context) { + SizeConfig.init(context); + return Scaffold( + body: Consumer( + builder: + (context, viewModel, child) => SafeArea( + child: Column( + children: [ + const DesktopNavigationWidget(currentIndex: 1), + const SizedBox(height: 64.0), + SizedBox( + width: 740, + child: Column( + children: [ + Expanded( + child: SizedBox( + child: SingleChildScrollView( + child: Column( + children: [ + const TabletDesktopAppbar( + title: + FinalCompletionOfDocumentsStrings + .completionOfDocuments, + ), + SizedBox(height: 32.0.h()), + + const SizedBox(height: 32.0), + const CommentBox(), + const SizedBox(height: 32.0), + FormCard(viewModel: viewModel), + const SizedBox(height: 40.0), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + BaseButton( + isEnabled: true, + onPressed: () {}, + width: 176, + backgroundColor: AppColors.primary10, + textColor: AppColors.mainBlue, + text: + FinalCompletionOfDocumentsStrings + .back, + ), + const SizedBox(width: 16.0), + BaseButton( + isEnabled: true, + onPressed: () {}, + width: 176, + text: + FinalCompletionOfDocumentsStrings + .next, + ), + ], + ), + const SizedBox(height: 35.0), + ], + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ); + } +} + +class FormCard extends StatelessWidget { + const FormCard({required this.viewModel, super.key}); + final FinalCompletionOfDocumentsViewModel viewModel; + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + border: Border.all(color: AppColors.borderColor), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: double.infinity, + height: 64.0, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + border: Border.all(color: AppColors.borderColor), + ), + alignment: AlignmentDirectional.centerStart, + child: Container( + width: 118, + height: 32, + decoration: BoxDecoration( + color: AppColors.yellow3, + borderRadius: BorderRadius.circular(8), + ), + alignment: Alignment.center, + child: const Text( + '50% Completed', + style: TextStyle(color: AppColors.yellow4), + ), + ), + ), + const SizedBox(height: 48.0), + Text( + FinalCompletionOfDocumentsStrings.numberOfServersListedTitle, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + const SizedBox(height: 12.0), + Text( + '12 servers across 2 data centers', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w400, + color: AppColors.grey80, + ), + ), + const SizedBox(height: 24), + Divider(color: AppColors.borderColor), + const SizedBox(height: 24), + Text( + FinalCompletionOfDocumentsStrings + .technicalTeamOrganizationChartUploadedTitle, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + const SizedBox(height: 12.0), + Text( + 'PDF submitted with full team roles and structure', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w400, + color: AppColors.grey80, + ), + ), + const SizedBox(height: 24), + Divider(color: AppColors.borderColor), + const SizedBox(height: 48), + _titleDropDownRow( + text: + FinalCompletionOfDocumentsStrings + .describeInfrastructureCapabilitiestitle, + ), + const SizedBox(height: 16), + _uploadFileCard(viewModel: viewModel), + const SizedBox(height: 40), + _titleDropDownRow( + text: + FinalCompletionOfDocumentsStrings + .uploadTechnicalTeamOrgChartTitle, + ), + const SizedBox(height: 16), + _describeYourTeamTextField(), + const SizedBox(height: 48), + _titleDropDownRow( + text: + FinalCompletionOfDocumentsStrings + .noCertificationInISO27001Title, + ), + const SizedBox(height: 16), + _uploadFileCard(viewModel: viewModel), + const SizedBox(height: 48), + _titleDropDownRow( + text: + FinalCompletionOfDocumentsStrings + .uploadCompletionCertificateTitle, + ), + const SizedBox(height: 16), + _uploadFileCard(viewModel: viewModel), + ], + ), + ); + } + + Widget _describeYourTeamTextField() { + return TextFormField( + maxLines: 5, + decoration: InputDecoration( + filled: true, + fillColor: AppColors.grey0, + hintText: FinalCompletionOfDocumentsStrings.describeYourTeamHint, + hintStyle: TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + border: OutlineInputBorder( + borderSide: const BorderSide(color: AppColors.secondaryborder2), + borderRadius: BorderRadius.circular(12), + ), + enabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: AppColors.secondaryborder2), + borderRadius: BorderRadius.circular(12), + ), + focusedBorder: OutlineInputBorder( + borderSide: const BorderSide(color: AppColors.secondaryborder2), + borderRadius: BorderRadius.circular(12), + ), + ), + ); + } + + Widget _uploadFileCard({ + required FinalCompletionOfDocumentsViewModel viewModel, + }) { + return InkWell( + onTap: () => viewModel.pickFile(), + child: Container( + width: double.infinity, + height: 140, + decoration: BoxDecoration(color: AppColors.grey0), + child: DottedBorder( + options: const RoundedRectDottedBorderOptions( + radius: Radius.circular(12), + dashPattern: [4, 4], + strokeWidth: 1, + color: AppColors.secondaryborder, + padding: EdgeInsets.all(16), + ), + + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SvgPicture.asset(AssetsManager.uploadFile), + const SizedBox(height: 12), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + FinalCompletionOfDocumentsStrings.chooseFile, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: AppColors.mainBlue, + ), + ), + const SizedBox(width: 4), + Text( + FinalCompletionOfDocumentsStrings.toUpload, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: AppColors.grey60, + ), + ), + ], + ), + const SizedBox(height: 8), + Text( + FinalCompletionOfDocumentsStrings.selectZipOrEtcTitle, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + ], + ), + ), + ), + ); + } + + Widget _titleDropDownRow({required String text}) { + return Row( + children: [ + SvgPicture.asset(AssetsManager.dangerFill), + const SizedBox(width: 8), + Text( + text, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + const Spacer(), + MainDropDown( + text: FinalCompletionOfDocumentsStrings.statusTitle, + items: const [ + FinalCompletionOfDocumentsStrings.statusWaitingForOthers, + FinalCompletionOfDocumentsStrings.statusToDo, + FinalCompletionOfDocumentsStrings.statusDone, + ], + onSelect: (String item) {}, + ), + ], + ); + } +} diff --git a/lib/views/final_completion_of_documents/pages/final_completion_of_documents_screen.dart b/lib/views/final_completion_of_documents/pages/final_completion_of_documents_screen.dart index fe981d2..f307f2f 100644 --- a/lib/views/final_completion_of_documents/pages/final_completion_of_documents_screen.dart +++ b/lib/views/final_completion_of_documents/pages/final_completion_of_documents_screen.dart @@ -1,316 +1,52 @@ -import 'package:dotted_border/dotted_border.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:provider/provider.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:tm_app/view_models/final_completion_of_documents_view_model.dart'; -import 'package:tm_app/views/final_completion_of_documents/strings/final_completion_of_documents_strings.dart'; -import 'package:tm_app/views/final_completion_of_documents/widgets/comment_box.dart'; -import 'package:tm_app/views/login/widgets/widgets.dart'; -import 'package:tm_app/views/shared/desktop_navigation_widget.dart'; -import 'package:tm_app/views/shared/tablet_desktop_appbar.dart'; +import 'package:tm_app/views/final_completion_of_documents/pages/desktop_final_completion_of_documents_page.dart'; +import 'package:tm_app/views/final_completion_of_documents/pages/tablet_final_completion_of_documents_page.dart'; -import '../../shared/main_drop_down.dart'; +import '../../../core/utils/size_config.dart'; +import '../../shared/responsive_builder.dart'; -class FinalCompletionOfDocumentsScreen extends StatelessWidget { +class FinalCompletionOfDocumentsScreen extends StatefulWidget { const FinalCompletionOfDocumentsScreen({super.key}); + @override + State createState() => + _FinalCompletionOfDocumentsScreenState(); +} + +class _FinalCompletionOfDocumentsScreenState + extends State { + // late final HomeViewModel _viewModel; + // late final TabNavigationService _tabService; + + @override + void initState() { + super.initState(); + // _viewModel = context.read(); + // _tabService = context.read(); + // _tabService.addListener(_onTabChanged); + } + + @override + void dispose() { + // _tabService.removeListener(_onTabChanged); + super.dispose(); + } + + // void _onTabChanged() { + // // Tab index 0 is Home + // if (_tabService.currentTabIndex == 0 && mounted) { + // _viewModel.init(); + // } + // } + @override Widget build(BuildContext context) { SizeConfig.init(context); - return Scaffold( - body: Consumer( - builder: - (context, viewModel, child) => SafeArea( - child: Column( - children: [ - const DesktopNavigationWidget(currentIndex: 1), - const SizedBox(height: 64.0), - Expanded( - child: SizedBox( - width: 740, - child: SingleChildScrollView( - child: Column( - children: [ - const TabletDesktopAppbar( - title: - FinalCompletionOfDocumentsStrings - .completionOfDocuments, - ), - SizedBox(height: 32.0.h()), - - const SizedBox(height: 32.0), - const CommentBox(), - const SizedBox(height: 32.0), - FormCard(viewModel: viewModel), - const SizedBox(height: 40.0), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - BaseButton( - isEnabled: true, - onPressed: () {}, - width: 176, - backgroundColor: AppColors.primary10, - textColor: AppColors.mainBlue, - text: FinalCompletionOfDocumentsStrings.back, - ), - const SizedBox(width: 16.0), - BaseButton( - isEnabled: true, - onPressed: () {}, - width: 176, - text: FinalCompletionOfDocumentsStrings.next, - ), - ], - ), - const SizedBox(height: 35.0), - ], - ), - ), - ), - ), - ], - ), - ), - ), - ); - } -} - -class FormCard extends StatelessWidget { - const FormCard({required this.viewModel, super.key}); - final FinalCompletionOfDocumentsViewModel viewModel; - - @override - Widget build(BuildContext context) { - return Container( - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - border: Border.all(color: AppColors.borderColor), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - height: 64.0, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - border: Border.all(color: AppColors.borderColor), - ), - alignment: AlignmentDirectional.centerStart, - child: Container( - width: 118, - height: 32, - decoration: BoxDecoration( - color: AppColors.yellow3, - borderRadius: BorderRadius.circular(8), - ), - alignment: Alignment.center, - child: const Text( - '50% Completed', - style: TextStyle(color: AppColors.yellow4), - ), - ), - ), - const SizedBox(height: 48.0), - Text( - FinalCompletionOfDocumentsStrings.numberOfServersListedTitle, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w400, - color: AppColors.grey60, - ), - ), - const SizedBox(height: 12.0), - Text( - '12 servers across 2 data centers', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w400, - color: AppColors.grey80, - ), - ), - const SizedBox(height: 24), - Divider(color: AppColors.borderColor), - const SizedBox(height: 24), - Text( - FinalCompletionOfDocumentsStrings - .technicalTeamOrganizationChartUploadedTitle, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w400, - color: AppColors.grey60, - ), - ), - const SizedBox(height: 12.0), - Text( - 'PDF submitted with full team roles and structure', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w400, - color: AppColors.grey80, - ), - ), - const SizedBox(height: 24), - Divider(color: AppColors.borderColor), - const SizedBox(height: 48), - _titleDropDownRow( - text: - FinalCompletionOfDocumentsStrings - .describeInfrastructureCapabilitiestitle, - ), - const SizedBox(height: 16), - _uploadFileCard(viewModel: viewModel), - const SizedBox(height: 40), - _titleDropDownRow( - text: - FinalCompletionOfDocumentsStrings - .uploadTechnicalTeamOrgChartTitle, - ), - const SizedBox(height: 16), - _describeYourTeamTextField(), - const SizedBox(height: 48), - _titleDropDownRow( - text: - FinalCompletionOfDocumentsStrings - .noCertificationInISO27001Title, - ), - const SizedBox(height: 16), - _uploadFileCard(viewModel: viewModel), - const SizedBox(height: 48), - _titleDropDownRow( - text: - FinalCompletionOfDocumentsStrings - .uploadCompletionCertificateTitle, - ), - const SizedBox(height: 16), - _uploadFileCard(viewModel: viewModel), - ], - ), - ); - } - - Widget _describeYourTeamTextField() { - return TextFormField( - maxLines: 5, - decoration: InputDecoration( - filled: true, - fillColor: AppColors.grey0, - hintText: FinalCompletionOfDocumentsStrings.describeYourTeamHint, - hintStyle: TextStyle( - fontSize: 12.0, - fontWeight: FontWeight.w400, - color: AppColors.grey60, - ), - border: OutlineInputBorder( - borderSide: const BorderSide(color: AppColors.secondaryborder2), - borderRadius: BorderRadius.circular(12), - ), - enabledBorder: OutlineInputBorder( - borderSide: const BorderSide(color: AppColors.secondaryborder2), - borderRadius: BorderRadius.circular(12), - ), - focusedBorder: OutlineInputBorder( - borderSide: const BorderSide(color: AppColors.secondaryborder2), - borderRadius: BorderRadius.circular(12), - ), - ), - ); - } - - Widget _uploadFileCard({ - required FinalCompletionOfDocumentsViewModel viewModel, - }) { - return InkWell( - onTap: () => viewModel.pickFile(), - child: Container( - width: double.infinity, - height: 140, - decoration: BoxDecoration(color: AppColors.grey0), - child: DottedBorder( - options: const RoundedRectDottedBorderOptions( - radius: Radius.circular(12), - dashPattern: [4, 4], - strokeWidth: 1, - color: AppColors.secondaryborder, - padding: EdgeInsets.all(16), - ), - - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SvgPicture.asset(AssetsManager.uploadFile), - const SizedBox(height: 12), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - FinalCompletionOfDocumentsStrings.chooseFile, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.mainBlue, - ), - ), - const SizedBox(width: 4), - Text( - FinalCompletionOfDocumentsStrings.toUpload, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.grey60, - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - FinalCompletionOfDocumentsStrings.selectZipOrEtcTitle, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w400, - color: AppColors.grey60, - ), - ), - ], - ), - ), - ), - ); - } - - Widget _titleDropDownRow({required String text}) { - return Row( - children: [ - SvgPicture.asset(AssetsManager.dangerFill), - const SizedBox(width: 8), - Text( - text, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - color: AppColors.grey60, - ), - ), - const Spacer(), - MainDropDown( - text: FinalCompletionOfDocumentsStrings.statusTitle, - items: const [ - FinalCompletionOfDocumentsStrings.statusWaitingForOthers, - FinalCompletionOfDocumentsStrings.statusToDo, - FinalCompletionOfDocumentsStrings.statusDone, - ], - onSelect: (String item) {}, - ), - ], + return const ResponsiveBuilder( + //mobile: MobileFinalCompletionOfDocumentsPage(), + mobile: TabletFinalCompletionOfDocumentsPage(), + tablet: TabletFinalCompletionOfDocumentsPage(), + desktop: DesktopFinalCompletionOfDocumentsPage(), ); } } diff --git a/lib/views/final_completion_of_documents/pages/mobile_final_completion_of_documents_page.dart b/lib/views/final_completion_of_documents/pages/mobile_final_completion_of_documents_page.dart new file mode 100644 index 0000000..c99bcb4 --- /dev/null +++ b/lib/views/final_completion_of_documents/pages/mobile_final_completion_of_documents_page.dart @@ -0,0 +1,314 @@ +// import 'package:dotted_border/dotted_border.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_svg/svg.dart'; +// import 'package:provider/provider.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:tm_app/view_models/final_completion_of_documents_view_model.dart'; +// import 'package:tm_app/views/final_completion_of_documents/strings/final_completion_of_documents_strings.dart'; +// import 'package:tm_app/views/final_completion_of_documents/widgets/comment_box.dart'; +// import 'package:tm_app/views/login/widgets/widgets.dart'; +// import 'package:tm_app/views/shared/tablet_desktop_appbar.dart'; + +// import '../../shared/main_drop_down.dart'; + +// class MobileFinalCompletionOfDocumentsPage extends StatelessWidget { +// const MobileFinalCompletionOfDocumentsPage({super.key}); + +// @override +// Widget build(BuildContext context) { +// SizeConfig.init(context); +// return Scaffold( +// body: Consumer( +// builder: +// (context, viewModel, child) => SafeArea( +// child: Column( +// children: [ +// const SizedBox(height: 64.0), +// Padding( +// padding: EdgeInsets.symmetric(vertical: 24.0.h()), +// child: Expanded( +// child: SingleChildScrollView( +// child: Column( +// children: [ +// const TabletDesktopAppbar( +// title: +// FinalCompletionOfDocumentsStrings +// .completionOfDocuments, +// ), +// SizedBox(height: 32.0.h()), + +// const SizedBox(height: 32.0), +// const CommentBox(), +// const SizedBox(height: 32.0), +// FormCard(viewModel: viewModel), +// const SizedBox(height: 40.0), +// Row( +// mainAxisAlignment: MainAxisAlignment.end, +// children: [ +// BaseButton( +// isEnabled: true, +// onPressed: () {}, +// width: 176, +// backgroundColor: AppColors.primary10, +// textColor: AppColors.mainBlue, +// text: FinalCompletionOfDocumentsStrings.back, +// ), +// const SizedBox(width: 16.0), +// BaseButton( +// isEnabled: true, +// onPressed: () {}, +// width: 176, +// text: FinalCompletionOfDocumentsStrings.next, +// ), +// ], +// ), +// const SizedBox(height: 35.0), +// ], +// ), +// ), +// ), +// ), +// ], +// ), +// ), +// ), +// ); +// } +// } + +// class FormCard extends StatelessWidget { +// const FormCard({required this.viewModel, super.key}); +// final FinalCompletionOfDocumentsViewModel viewModel; + +// @override +// Widget build(BuildContext context) { +// return Container( +// width: double.infinity, +// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), +// decoration: BoxDecoration( +// borderRadius: BorderRadius.circular(4), +// border: Border.all(color: AppColors.borderColor), +// ), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Container( +// width: double.infinity, +// height: 64.0, +// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), +// decoration: BoxDecoration( +// borderRadius: BorderRadius.circular(4), +// border: Border.all(color: AppColors.borderColor), +// ), +// alignment: AlignmentDirectional.centerStart, +// child: Container( +// width: 118, +// height: 32, +// decoration: BoxDecoration( +// color: AppColors.yellow3, +// borderRadius: BorderRadius.circular(8), +// ), +// alignment: Alignment.center, +// child: const Text( +// '50% Completed', +// style: TextStyle(color: AppColors.yellow4), +// ), +// ), +// ), +// const SizedBox(height: 48.0), +// Text( +// FinalCompletionOfDocumentsStrings.numberOfServersListedTitle, +// style: TextStyle( +// fontSize: 16.0, +// fontWeight: FontWeight.w400, +// color: AppColors.grey60, +// ), +// ), +// const SizedBox(height: 12.0), +// Text( +// '12 servers across 2 data centers', +// style: TextStyle( +// fontSize: 16.0, +// fontWeight: FontWeight.w400, +// color: AppColors.grey80, +// ), +// ), +// const SizedBox(height: 24), +// Divider(color: AppColors.borderColor), +// const SizedBox(height: 24), +// Text( +// FinalCompletionOfDocumentsStrings +// .technicalTeamOrganizationChartUploadedTitle, +// style: TextStyle( +// fontSize: 16.0, +// fontWeight: FontWeight.w400, +// color: AppColors.grey60, +// ), +// ), +// const SizedBox(height: 12.0), +// Text( +// 'PDF submitted with full team roles and structure', +// style: TextStyle( +// fontSize: 16.0, +// fontWeight: FontWeight.w400, +// color: AppColors.grey80, +// ), +// ), +// const SizedBox(height: 24), +// Divider(color: AppColors.borderColor), +// const SizedBox(height: 48), +// _titleDropDownRow( +// text: +// FinalCompletionOfDocumentsStrings +// .describeInfrastructureCapabilitiestitle, +// ), +// const SizedBox(height: 16), +// _uploadFileCard(viewModel: viewModel), +// const SizedBox(height: 40), +// _titleDropDownRow( +// text: +// FinalCompletionOfDocumentsStrings +// .uploadTechnicalTeamOrgChartTitle, +// ), +// const SizedBox(height: 16), +// _describeYourTeamTextField(), +// const SizedBox(height: 48), +// _titleDropDownRow( +// text: +// FinalCompletionOfDocumentsStrings +// .noCertificationInISO27001Title, +// ), +// const SizedBox(height: 16), +// _uploadFileCard(viewModel: viewModel), +// const SizedBox(height: 48), +// _titleDropDownRow( +// text: +// FinalCompletionOfDocumentsStrings +// .uploadCompletionCertificateTitle, +// ), +// const SizedBox(height: 16), +// _uploadFileCard(viewModel: viewModel), +// ], +// ), +// ); +// } + +// Widget _describeYourTeamTextField() { +// return TextFormField( +// maxLines: 5, +// decoration: InputDecoration( +// filled: true, +// fillColor: AppColors.grey0, +// hintText: FinalCompletionOfDocumentsStrings.describeYourTeamHint, +// hintStyle: TextStyle( +// fontSize: 12.0, +// fontWeight: FontWeight.w400, +// color: AppColors.grey60, +// ), +// border: OutlineInputBorder( +// borderSide: const BorderSide(color: AppColors.secondaryborder2), +// borderRadius: BorderRadius.circular(12), +// ), +// enabledBorder: OutlineInputBorder( +// borderSide: const BorderSide(color: AppColors.secondaryborder2), +// borderRadius: BorderRadius.circular(12), +// ), +// focusedBorder: OutlineInputBorder( +// borderSide: const BorderSide(color: AppColors.secondaryborder2), +// borderRadius: BorderRadius.circular(12), +// ), +// ), +// ); +// } + +// Widget _uploadFileCard({ +// required FinalCompletionOfDocumentsViewModel viewModel, +// }) { +// return InkWell( +// onTap: () => viewModel.pickFile(), +// child: Container( +// width: double.infinity, +// height: 140, +// decoration: BoxDecoration(color: AppColors.grey0), +// child: DottedBorder( +// options: const RoundedRectDottedBorderOptions( +// radius: Radius.circular(12), +// dashPattern: [4, 4], +// strokeWidth: 1, +// color: AppColors.secondaryborder, +// padding: EdgeInsets.all(16), +// ), + +// child: Column( +// mainAxisAlignment: MainAxisAlignment.center, +// crossAxisAlignment: CrossAxisAlignment.center, +// children: [ +// SvgPicture.asset(AssetsManager.uploadFile), +// const SizedBox(height: 12), +// Row( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// const Text( +// FinalCompletionOfDocumentsStrings.chooseFile, +// style: TextStyle( +// fontSize: 14, +// fontWeight: FontWeight.w500, +// color: AppColors.mainBlue, +// ), +// ), +// const SizedBox(width: 4), +// Text( +// FinalCompletionOfDocumentsStrings.toUpload, +// style: TextStyle( +// fontSize: 14, +// fontWeight: FontWeight.w500, +// color: AppColors.grey60, +// ), +// ), +// ], +// ), +// const SizedBox(height: 8), +// Text( +// FinalCompletionOfDocumentsStrings.selectZipOrEtcTitle, +// style: TextStyle( +// fontSize: 12, +// fontWeight: FontWeight.w400, +// color: AppColors.grey60, +// ), +// ), +// ], +// ), +// ), +// ), +// ); +// } + +// Widget _titleDropDownRow({required String text}) { +// return Row( +// children: [ +// SvgPicture.asset(AssetsManager.dangerFill), +// const SizedBox(width: 8), +// Text( +// text, +// style: TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.w400, +// color: AppColors.grey60, +// ), +// ), +// const Spacer(), +// MainDropDown( +// text: FinalCompletionOfDocumentsStrings.statusTitle, +// items: const [ +// FinalCompletionOfDocumentsStrings.statusWaitingForOthers, +// FinalCompletionOfDocumentsStrings.statusToDo, +// FinalCompletionOfDocumentsStrings.statusDone, +// ], +// onSelect: (String item) {}, +// ), +// ], +// ); +// } +// } diff --git a/lib/views/final_completion_of_documents/pages/tablet_final_completion_of_documents_page.dart b/lib/views/final_completion_of_documents/pages/tablet_final_completion_of_documents_page.dart new file mode 100644 index 0000000..6937edf --- /dev/null +++ b/lib/views/final_completion_of_documents/pages/tablet_final_completion_of_documents_page.dart @@ -0,0 +1,343 @@ +import 'package:dotted_border/dotted_border.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:provider/provider.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:tm_app/view_models/final_completion_of_documents_view_model.dart'; +import 'package:tm_app/views/final_completion_of_documents/strings/final_completion_of_documents_strings.dart'; +import 'package:tm_app/views/final_completion_of_documents/widgets/comment_box.dart'; +import 'package:tm_app/views/login/widgets/widgets.dart'; +import 'package:tm_app/views/shared/main_drop_down.dart'; +import 'package:tm_app/views/shared/tablet_desktop_appbar.dart'; +import 'package:tm_app/views/shared/tablet_navigation_widget.dart'; +import 'package:tm_app/views/shared/tender_app_bar.dart'; + +class TabletFinalCompletionOfDocumentsPage extends StatelessWidget { + const TabletFinalCompletionOfDocumentsPage({super.key}); + + @override + Widget build(BuildContext context) { + final GlobalKey key = GlobalKey(); + SizeConfig.init(context); + + return Scaffold( + key: key, + backgroundColor: AppColors.backgroundColor, + appBar: tabletAppBar( + title: FinalCompletionOfDocumentsStrings.completionOfDocuments, + key: key, + context: context, + ), + drawer: const TabletNavigationWidget(currentIndex: 1), + body: Consumer( + builder: (context, viewModel, _) { + return SafeArea( + child: Center( + child: SizedBox( + width: 720, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 24.0.h()), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const TabletDesktopAppbar( + title: + FinalCompletionOfDocumentsStrings + .completionOfDocuments, + haveFilter: false, + ), + Expanded( + child: SingleChildScrollView( + padding: EdgeInsets.symmetric(vertical: 32.0.h()), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const CommentBox(), + SizedBox(height: 32.0.h()), + FormCard(viewModel: viewModel), + SizedBox(height: 40.0.h()), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + BaseButton( + isEnabled: true, + onPressed: () {}, + width: 176.0.w(), + backgroundColor: AppColors.primary10, + textColor: AppColors.mainBlue, + text: + FinalCompletionOfDocumentsStrings.back, + ), + SizedBox(width: 16.0.w()), + BaseButton( + isEnabled: true, + onPressed: () {}, + width: 176.0.w(), + text: + FinalCompletionOfDocumentsStrings.next, + ), + ], + ), + SizedBox(height: 35.0.h()), + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + }, + ), + ); + } +} + +class FormCard extends StatelessWidget { + const FormCard({required this.viewModel, super.key}); + final FinalCompletionOfDocumentsViewModel viewModel; + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + padding: EdgeInsets.symmetric(horizontal: 16.0.w(), vertical: 24.0.h()), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + border: Border.all(color: AppColors.borderColor), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _progressCard(), + SizedBox(height: 48.0.h()), + _infoSection( + title: FinalCompletionOfDocumentsStrings.numberOfServersListedTitle, + value: '12 servers across 2 data centers', + ), + SizedBox(height: 24.0.h()), + Divider(color: AppColors.borderColor), + SizedBox(height: 24.0.h()), + _infoSection( + title: + FinalCompletionOfDocumentsStrings + .technicalTeamOrganizationChartUploadedTitle, + value: 'PDF submitted with full team roles and structure', + ), + SizedBox(height: 24.0.h()), + Divider(color: AppColors.borderColor), + SizedBox(height: 48.0.h()), + _titleDropDownRow( + text: + FinalCompletionOfDocumentsStrings + .describeInfrastructureCapabilitiestitle, + ), + SizedBox(height: 16.0.h()), + _uploadFileCard(viewModel: viewModel), + SizedBox(height: 40.0.h()), + _titleDropDownRow( + text: + FinalCompletionOfDocumentsStrings + .uploadTechnicalTeamOrgChartTitle, + ), + SizedBox(height: 16.0.h()), + _describeYourTeamTextField(), + SizedBox(height: 48.0.h()), + _titleDropDownRow( + text: + FinalCompletionOfDocumentsStrings + .noCertificationInISO27001Title, + ), + SizedBox(height: 16.0.h()), + _uploadFileCard(viewModel: viewModel), + SizedBox(height: 48.0.h()), + _titleDropDownRow( + text: + FinalCompletionOfDocumentsStrings + .uploadCompletionCertificateTitle, + ), + SizedBox(height: 16.0.h()), + _uploadFileCard(viewModel: viewModel), + ], + ), + ); + } + + Widget _progressCard() { + return Container( + width: double.infinity, + height: 64.0.h(), + padding: EdgeInsets.symmetric(horizontal: 16.0.w(), vertical: 16.0.h()), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + border: Border.all(color: AppColors.borderColor), + ), + alignment: AlignmentDirectional.centerStart, + child: Container( + width: 118.0.w(), + height: 32.0.h(), + decoration: BoxDecoration( + color: AppColors.yellow3, + borderRadius: BorderRadius.circular(8), + ), + alignment: Alignment.center, + child: Text( + '50% Completed', + style: TextStyle(color: AppColors.yellow4, fontSize: 14.0.sp()), + ), + ), + ); + } + + Widget _infoSection({required String title, required String value}) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + SizedBox(height: 12.0.h()), + Text( + value, + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey80, + ), + ), + ], + ); + } + + Widget _describeYourTeamTextField() { + return TextFormField( + maxLines: 5, + decoration: InputDecoration( + filled: true, + fillColor: AppColors.grey0, + hintText: FinalCompletionOfDocumentsStrings.describeYourTeamHint, + hintStyle: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + border: OutlineInputBorder( + borderSide: const BorderSide(color: AppColors.secondaryborder2), + borderRadius: BorderRadius.circular(12), + ), + enabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: AppColors.secondaryborder2), + borderRadius: BorderRadius.circular(12), + ), + focusedBorder: OutlineInputBorder( + borderSide: const BorderSide(color: AppColors.secondaryborder2), + borderRadius: BorderRadius.circular(12), + ), + ), + ); + } + + Widget _uploadFileCard({ + required FinalCompletionOfDocumentsViewModel viewModel, + }) { + return InkWell( + onTap: () => viewModel.pickFile(), + child: Container( + width: double.infinity, + height: 140.0.h(), + decoration: BoxDecoration( + color: AppColors.grey0, + borderRadius: BorderRadius.circular(12), + ), + child: DottedBorder( + options: RoundedRectDottedBorderOptions( + radius: const Radius.circular(12), + dashPattern: const [4, 4], + strokeWidth: 1, + color: AppColors.secondaryborder, + padding: EdgeInsets.all(16.0.w()), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset(AssetsManager.uploadFile, height: 32.0.h()), + SizedBox(height: 12.0.h()), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + FinalCompletionOfDocumentsStrings.chooseFile, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.mainBlue, + ), + ), + SizedBox(width: 4.0.w()), + Text( + FinalCompletionOfDocumentsStrings.toUpload, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.grey60, + ), + ), + ], + ), + SizedBox(height: 8.0.h()), + Text( + FinalCompletionOfDocumentsStrings.selectZipOrEtcTitle, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + ], + ), + ), + ), + ); + } + + Widget _titleDropDownRow({required String text}) { + return Row( + children: [ + SvgPicture.asset( + AssetsManager.dangerFill, + height: 20.0.h(), + width: 20.0.w(), + ), + SizedBox(width: 8.0.w()), + Expanded( + child: Text( + text, + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey60, + ), + ), + ), + MainDropDown( + text: FinalCompletionOfDocumentsStrings.statusTitle, + items: const [ + FinalCompletionOfDocumentsStrings.statusWaitingForOthers, + FinalCompletionOfDocumentsStrings.statusToDo, + FinalCompletionOfDocumentsStrings.statusDone, + ], + onSelect: (String item) {}, + ), + ], + ); + } +} diff --git a/lib/views/shared/select_submission_dialog.dart b/lib/views/shared/select_submission_dialog.dart index 51afc56..fc6acbc 100644 --- a/lib/views/shared/select_submission_dialog.dart +++ b/lib/views/shared/select_submission_dialog.dart @@ -29,7 +29,7 @@ class _SelectSubmissionDialogState extends State { height: 300, padding: EdgeInsets.symmetric(horizontal: 24.0.w(), vertical: 16.0.h()), decoration: BoxDecoration( - color: Colors.white, + color: AppColors.backgroundColor, borderRadius: BorderRadius.circular(16), ), child: Column( @@ -65,28 +65,57 @@ class _SelectSubmissionDialogState extends State { SizedBox(height: 8.0.h()), Align( alignment: Alignment.centerRight, - child: InkWell( - onTap: () { - widget.onConfirm(type); - context.pop(); - }, - child: Container( - width: 150, - height: 56.0, - decoration: BoxDecoration( - color: AppColors.primary20, - borderRadius: BorderRadius.circular(100), - ), - alignment: Alignment.center, - child: Text( - CommonStrings.confirm, - style: TextStyle( - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - color: AppColors.mainBlue, + child: Row( + children: [ + const Spacer(), + InkWell( + onTap: () { + context.pop(); + }, + child: Container( + width: 150, + height: 56.0, + decoration: BoxDecoration( + color: AppColors.red10, + borderRadius: BorderRadius.circular(100), + ), + alignment: Alignment.center, + child: Text( + CommonStrings.cancel, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.red20, + ), + ), ), ), - ), + SizedBox(width: 10.0.w()), + + InkWell( + onTap: () { + widget.onConfirm(type); + context.pop(); + }, + child: Container( + width: 150, + height: 56.0, + decoration: BoxDecoration( + color: AppColors.primary20, + borderRadius: BorderRadius.circular(100), + ), + alignment: Alignment.center, + child: Text( + CommonStrings.confirm, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.mainBlue, + ), + ), + ), + ), + ], ), ), ], From 919b9fb2edc330243a6faae60089c167c0628e88 Mon Sep 17 00:00:00 2001 From: amirrezaghabeli Date: Mon, 13 Oct 2025 14:51:39 +0330 Subject: [PATCH 2/2] Refactor completion of documents routing and UI components - Removed unused mobile route for completion of documents. - Updated app routes to reflect the removal of the mobile route. - Enhanced the desktop and mobile pages for completion of documents with improved layout and added TabletDesktopAppbar. - Introduced meeting time handling in TenderDetailActions, integrating new bottom sheet and dialog components for better user interaction. - Added meeting time state management in TenderDetailViewModel. - Cleaned up deprecated files related to meeting time selection. --- lib/core/routes/app_routes.dart | 34 ++- lib/core/routes/app_routes.g.dart | 28 --- lib/view_models/tender_detail_view_model.dart | 7 + .../pages/d_completion_of_documents_page.dart | 37 ++-- .../pages/m_completion_of_documents_page.dart | 30 +-- .../detail/pages/detail_desktop_page.dart | 1 + .../detail/pages/detail_mobile_page.dart | 6 +- .../detail/pages/detail_tablet_page.dart | 6 +- .../strings/tender_details_strings.dart | 2 + ...et.dart => meeting_time_bottom_sheet.dart} | 125 +++++------ .../detail/widgets/meeting_time_dialog.dart | 198 ++++++++++++++++++ ...show_select_meeting_time_bottom_sheet.dart | 29 --- .../detail/widgets/tender_detail_action.dart | 126 +++++++---- ...op_final_completion_of_documents_page.dart | 101 +++++---- 14 files changed, 448 insertions(+), 282 deletions(-) rename lib/views/detail/widgets/{select_meeting_time_bottom_sheet.dart => meeting_time_bottom_sheet.dart} (60%) create mode 100644 lib/views/detail/widgets/meeting_time_dialog.dart delete mode 100644 lib/views/detail/widgets/show_select_meeting_time_bottom_sheet.dart diff --git a/lib/core/routes/app_routes.dart b/lib/core/routes/app_routes.dart index e7bc7ab..5536360 100644 --- a/lib/core/routes/app_routes.dart +++ b/lib/core/routes/app_routes.dart @@ -3,7 +3,6 @@ import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tm_app/views/completion_of_documents/pages/complectopn_of_documents_screen.dart'; -import 'package:tm_app/views/completion_of_documents/pages/m_completion_of_documents_page.dart'; import 'package:tm_app/views/detail/pages/detail_screen.dart'; import 'package:tm_app/views/forget_password_create/pages/forgot_password_create_screen.dart'; import 'package:tm_app/views/forget_password_otp/pages/forgot_password_otp_screen.dart'; @@ -236,17 +235,14 @@ class FinalCompletionOfDocumentsRouteData extends GoRouteData } } -@TypedGoRoute( - path: '/completion_of_documents', -) +@TypedGoRoute(path: '/completion_of_documents') class CompletionOfDocumentsRouteData extends GoRouteData with _$CompletionOfDocumentsRouteData { const CompletionOfDocumentsRouteData(); @override Widget build(BuildContext context, GoRouterState state) { - return const CompletionOfDocumentsScreen(); - + return const CompletionOfDocumentsScreen(); } } @@ -260,20 +256,20 @@ class LikedTendersRouteData extends GoRouteData with _$LikedTendersRouteData { } } -@TypedGoRoute( - path: '/completion-of-documents', -) -class CompletionOfDocumentsMobileRouteData extends GoRouteData - with _$CompletionOfDocumentsMobileRouteData { - const CompletionOfDocumentsMobileRouteData(); +// @TypedGoRoute( +// path: '/completion-of-documents', +// ) +// class CompletionOfDocumentsMobileRouteData extends GoRouteData +// with _$CompletionOfDocumentsMobileRouteData { +// const CompletionOfDocumentsMobileRouteData(); - @override - Widget build(BuildContext context, GoRouterState state) { - return finalCompletionProvider( - child: const CompletionOfDocumentsMobilePage(), - ); - } -} +// @override +// Widget build(BuildContext context, GoRouterState state) { +// return finalCompletionProvider( +// child: const CompletionOfDocumentsMobilePage(), +// ); +// } +// } @TypedGoRoute(path: '/tender-detail') class TenderDetailRouteData extends GoRouteData with _$TenderDetailRouteData { diff --git a/lib/core/routes/app_routes.g.dart b/lib/core/routes/app_routes.g.dart index 6c2b7b6..f462082 100644 --- a/lib/core/routes/app_routes.g.dart +++ b/lib/core/routes/app_routes.g.dart @@ -14,7 +14,6 @@ List get $appRoutes => [ $finalCompletionOfDocumentsRouteData, $completionOfDocumentsRouteData, $likedTendersRouteData, - $completionOfDocumentsMobileRouteData, $tenderDetailRouteData, $forgotPasswordRouteData, $forgotPasswordOtpRouteData, @@ -349,33 +348,6 @@ mixin _$LikedTendersRouteData on GoRouteData { void replace(BuildContext context) => context.replace(location); } -RouteBase get $completionOfDocumentsMobileRouteData => GoRouteData.$route( - path: '/completion-of-documents', - - factory: _$CompletionOfDocumentsMobileRouteData._fromState, -); - -mixin _$CompletionOfDocumentsMobileRouteData on GoRouteData { - static CompletionOfDocumentsMobileRouteData _fromState(GoRouterState state) => - const CompletionOfDocumentsMobileRouteData(); - - @override - String get location => GoRouteData.$location('/completion-of-documents'); - - @override - void go(BuildContext context) => context.go(location); - - @override - Future push(BuildContext context) => context.push(location); - - @override - void pushReplacement(BuildContext context) => - context.pushReplacement(location); - - @override - void replace(BuildContext context) => context.replace(location); -} - RouteBase get $tenderDetailRouteData => GoRouteData.$route( path: '/tender-detail', diff --git a/lib/view_models/tender_detail_view_model.dart b/lib/view_models/tender_detail_view_model.dart index 86049da..d5b0b0d 100644 --- a/lib/view_models/tender_detail_view_model.dart +++ b/lib/view_models/tender_detail_view_model.dart @@ -28,6 +28,7 @@ class TenderDetailViewModel with ChangeNotifier { TenderApprovalsData? _tenderApprovalData; bool approvalStatus = false; String _status = ''; + String _meetingTime = ''; bool get isLoading => _isLoading; bool get isSubmitApprovalLoading => _isSubmitApprovalLoading; @@ -36,6 +37,12 @@ class TenderDetailViewModel with ChangeNotifier { TenderData? get tenderDetail => _tenderDetail; TenderApprovalsData? get tenderApprovalData => _tenderApprovalData; String get status => _status; + String get meetingTime => _meetingTime; + + set meetingTime(String value) { + _meetingTime = value; + notifyListeners(); + } Future getTenderDetail({required String id}) async { _isLoading = true; diff --git a/lib/views/completion_of_documents/pages/d_completion_of_documents_page.dart b/lib/views/completion_of_documents/pages/d_completion_of_documents_page.dart index bd97161..6f82ce5 100644 --- a/lib/views/completion_of_documents/pages/d_completion_of_documents_page.dart +++ b/lib/views/completion_of_documents/pages/d_completion_of_documents_page.dart @@ -6,6 +6,8 @@ import 'package:tm_app/core/utils/size_config.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/desktop_navigation_widget.dart'; +import 'package:tm_app/views/shared/tablet_desktop_appbar.dart' + show TabletDesktopAppbar; class CompletionOfDocumentsDesktopPage extends StatelessWidget { const CompletionOfDocumentsDesktopPage({super.key}); @@ -17,36 +19,24 @@ class CompletionOfDocumentsDesktopPage extends StatelessWidget { body: Column( children: [ const DesktopNavigationWidget(currentIndex: 0), - SizedBox( - width: 760, + Expanded( child: SingleChildScrollView( - child: Center( - child: SizedBox( - child: Padding( - padding: EdgeInsets.symmetric(vertical: 24.0.h()), - child: Expanded( + child: SizedBox( + width: double.infinity, + child: Center( + child: SizedBox( + width: 760, + child: Center( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - SvgPicture.asset( - AssetsManager.arrowLeft, - width: 24.0.w(), - height: 24.0.h(), - ), - SizedBox(width: 8.0.w()), - Text( + SizedBox(height: 40.0.h()), + const TabletDesktopAppbar( + title: CompletionOfDocumentsStrings .completionOfDocuments, - style: TextStyle( - color: AppColors.grey70, - fontSize: 16.0.sp(), - fontWeight: FontWeight.w600, - ), - ), - ], ), + SizedBox(height: 24.0.h()), _deadlineContainer(), @@ -78,6 +68,7 @@ class CompletionOfDocumentsDesktopPage extends StatelessWidget { textColor: AppColors.textBlue, backgroundColor: AppColors.primary30, ), + SizedBox(height: 24.0.h()), ], ), ), 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 f7db376..bed33ca 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 @@ -6,6 +6,8 @@ import 'package:tm_app/core/utils/size_config.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}); @@ -13,10 +15,10 @@ class CompletionOfDocumentsMobilePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.backgroundColor, - // appBar: appBar( - // context: context, - // title: CompletionOfDocumentsStrings.completionOfDocuments, - // ), + appBar: appBar( + context: context, + title: CompletionOfDocumentsStrings.completionOfDocuments, + ), body: SafeArea( child: SingleChildScrollView( padding: EdgeInsets.symmetric( @@ -26,26 +28,6 @@ class CompletionOfDocumentsMobilePage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - SvgPicture.asset( - AssetsManager.arrowLeft, - width: 24.0.w(), - height: 24.0.h(), - ), - SizedBox(width: 8.0.w()), - Text( - CompletionOfDocumentsStrings.completionOfDocuments, - style: TextStyle( - color: AppColors.grey70, - fontSize: 16.0.sp(), - fontWeight: FontWeight.w600, - ), - ), - ], - ), - SizedBox(height: 24.0.h()), - Container( width: double.infinity, height: 24.0.h(), diff --git a/lib/views/detail/pages/detail_desktop_page.dart b/lib/views/detail/pages/detail_desktop_page.dart index 2244d03..6cf75d1 100644 --- a/lib/views/detail/pages/detail_desktop_page.dart +++ b/lib/views/detail/pages/detail_desktop_page.dart @@ -126,6 +126,7 @@ class _TenderDetailDesktopPageState extends State { TenderDetailActions( isScreenBig: true, detail: detail, + viewModel: viewModel, ), ], ), diff --git a/lib/views/detail/pages/detail_mobile_page.dart b/lib/views/detail/pages/detail_mobile_page.dart index 797c2cc..0d76ffa 100644 --- a/lib/views/detail/pages/detail_mobile_page.dart +++ b/lib/views/detail/pages/detail_mobile_page.dart @@ -114,7 +114,11 @@ class _TenderDetailMobilePageState extends State { SizedBox(height: 24.0.h()), TenderDetailCard(detail: detail), SizedBox(height: 24.0.h()), - TenderDetailActions(isScreenBig: false, detail: detail), + TenderDetailActions( + isScreenBig: false, + detail: detail, + viewModel: viewModel, + ), ], ), ), diff --git a/lib/views/detail/pages/detail_tablet_page.dart b/lib/views/detail/pages/detail_tablet_page.dart index e8eef3e..a953d03 100644 --- a/lib/views/detail/pages/detail_tablet_page.dart +++ b/lib/views/detail/pages/detail_tablet_page.dart @@ -125,7 +125,11 @@ class _TenderDetailTabletPageState extends State { SizedBox(height: 28.0.h()), TenderDetailCard(detail: detail), SizedBox(height: 24.0.h()), - TenderDetailActions(isScreenBig: true, detail: detail), + TenderDetailActions( + isScreenBig: true, + detail: detail, + viewModel: viewModel, + ), ], ), ), diff --git a/lib/views/detail/strings/tender_details_strings.dart b/lib/views/detail/strings/tender_details_strings.dart index 9d152fd..61b36c8 100644 --- a/lib/views/detail/strings/tender_details_strings.dart +++ b/lib/views/detail/strings/tender_details_strings.dart @@ -37,4 +37,6 @@ class TenderDetailsStrings { static const String pleaseReplyBy = 'If you’d like to join, Please Reply by '; static const String lastDayToPrepareProposal = 'Last day to prepare proposal is '; + static const String meetingTimeSuccessfullySet = + 'meeting time successfully set'; } diff --git a/lib/views/detail/widgets/select_meeting_time_bottom_sheet.dart b/lib/views/detail/widgets/meeting_time_bottom_sheet.dart similarity index 60% rename from lib/views/detail/widgets/select_meeting_time_bottom_sheet.dart rename to lib/views/detail/widgets/meeting_time_bottom_sheet.dart index be383a6..953f8b6 100644 --- a/lib/views/detail/widgets/select_meeting_time_bottom_sheet.dart +++ b/lib/views/detail/widgets/meeting_time_bottom_sheet.dart @@ -1,21 +1,20 @@ import 'package:flutter/material.dart'; -import 'package:tm_app/core/routes/app_routes.dart'; -import 'package:tm_app/core/theme/colors.dart'; +import 'package:go_router/go_router.dart'; import 'package:tm_app/core/utils/size_config.dart'; -import 'package:tm_app/views/detail/strings/tender_details_strings.dart'; -class SelectMeetingTimeBottomSheet extends StatefulWidget { - const SelectMeetingTimeBottomSheet({required this.onConfirm, required this.isDialog, super.key}); +import '../../../core/routes/app_routes.dart'; +import '../../../core/theme/colors.dart'; +import '../strings/tender_details_strings.dart'; + +class MeetingTimeBottomSheet extends StatefulWidget { + const MeetingTimeBottomSheet({required this.onConfirm, super.key}); final ValueChanged onConfirm; - final bool isDialog; @override - State createState() => - _SelectMeetingTimeBottomSheetState(); + State createState() => _MeetingTimeBottomSheetState(); } -class _SelectMeetingTimeBottomSheetState - extends State { +class _MeetingTimeBottomSheetState extends State { int selectedType = 0; late String type = ''; @@ -26,7 +25,6 @@ class _SelectMeetingTimeBottomSheetState {'title': 'Sun 2025-06-18', 'value': 'mode4', 'time': '16:00'}, {'title': 'Sun 2025-06-19', 'value': 'mode5', 'time': '18:00'}, ]; - @override Widget build(BuildContext context) { return Wrap( @@ -36,7 +34,7 @@ class _SelectMeetingTimeBottomSheetState padding: EdgeInsets.fromLTRB(24.0.w(), 24.0.h(), 24.0.w(), 33.0.h()), decoration: BoxDecoration( color: AppColors.backgroundColor, - borderRadius: widget.isDialog ? const BorderRadius.all(Radius.circular(16.0)) : const BorderRadius.only( + borderRadius: const BorderRadius.only( topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0), ), @@ -77,8 +75,9 @@ class _SelectMeetingTimeBottomSheetState SizedBox(height: 8.0.h()), InkWell( onTap: () { - const CompletionOfDocumentsMobileRouteData().push(context); - //context.pop(); + widget.onConfirm(type); + context.pop(); + const CompletionOfDocumentsRouteData().push(context); }, child: Container( width: double.infinity, @@ -118,61 +117,65 @@ class _SelectMeetingTimeBottomSheetState color: isSelected ? AppColors.mainBlue : AppColors.grey40, ), ), - child: InkWell( - onTap: onTap, - child: SizedBox( - width: double.infinity, - height: 40.0.h(), - child: Row( - children: [ - Container( - width: 20.0.w(), - height: 20.0.w(), - margin: EdgeInsets.symmetric( - horizontal: 10.0.w(), - vertical: 10.0.h(), - ), - padding: const EdgeInsets.all(3), - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: isSelected ? AppColors.mainBlue : AppColors.grey70, - width: 2.0, + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: onTap, + child: SizedBox( + width: double.infinity, + height: 40.0.h(), + child: Row( + children: [ + Container( + width: 20.0.w(), + height: 20.0.w(), + margin: EdgeInsets.symmetric( + horizontal: 10.0.w(), + vertical: 10.0.h(), ), - ), - alignment: Alignment.center, - child: Container( + padding: const EdgeInsets.all(3), decoration: BoxDecoration( shape: BoxShape.circle, - color: isSelected ? AppColors.mainBlue : Colors.transparent, + border: Border.all( + color: isSelected ? AppColors.mainBlue : AppColors.grey70, + width: 2.0, + ), + ), + alignment: Alignment.center, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: + isSelected ? AppColors.mainBlue : Colors.transparent, + ), ), ), - ), - Expanded( - child: Row( - children: [ - Text( - title, - style: TextStyle( - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - color: AppColors.grey80, + Expanded( + child: Row( + children: [ + Text( + title, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.grey80, + ), ), - ), - const Spacer(), - Text( - time, - style: TextStyle( - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - color: AppColors.grey80, + const Spacer(), + Text( + time, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.grey80, + ), ), - ), - SizedBox(width: 10.0.w()), - ], + SizedBox(width: 10.0.w()), + ], + ), ), - ), - ], + ], + ), ), ), ), diff --git a/lib/views/detail/widgets/meeting_time_dialog.dart b/lib/views/detail/widgets/meeting_time_dialog.dart new file mode 100644 index 0000000..b643684 --- /dev/null +++ b/lib/views/detail/widgets/meeting_time_dialog.dart @@ -0,0 +1,198 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:tm_app/core/routes/app_routes.dart'; +import 'package:tm_app/core/theme/colors.dart'; +import 'package:tm_app/core/utils/size_config.dart'; +import 'package:tm_app/views/detail/strings/tender_details_strings.dart'; + +class MeetingTimeDialog extends StatefulWidget { + const MeetingTimeDialog({required this.onConfirm, super.key}); + final ValueChanged onConfirm; + + @override + State createState() => _MeetingTimeDialogState(); +} + +class _MeetingTimeDialogState extends State { + int selectedType = 0; + late String type = ''; + + final List> times = [ + {'title': 'Sun 2025-06-15', 'value': 'mode1', 'time': '10:00'}, + {'title': 'Sun 2025-06-16', 'value': 'mode2', 'time': '12:00'}, + {'title': 'Sun 2025-06-17', 'value': 'mode3', 'time': '14:00'}, + {'title': 'Sun 2025-06-18', 'value': 'mode4', 'time': '16:00'}, + {'title': 'Sun 2025-06-19', 'value': 'mode5', 'time': '18:00'}, + ]; + + @override + Widget build(BuildContext context) { + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + side: BorderSide.none, + ), + + insetPadding: const EdgeInsets.symmetric(horizontal: 150), + child: Wrap( + children: [ + Container( + // width: double.infinity, + padding: EdgeInsets.fromLTRB( + 24.0.w(), + 24.0.h(), + 24.0.w(), + 33.0.h(), + ), + + decoration: BoxDecoration( + color: AppColors.backgroundColor, + borderRadius: const BorderRadius.all(Radius.circular(16.0)), + ), + child: Column( + children: [ + Text( + TenderDetailsStrings.meetingTime, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey70, + ), + ), + SizedBox(height: 15.0.h()), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: times.length, + itemBuilder: (context, index) { + final item = times[index]; + return Padding( + padding: EdgeInsets.only(bottom: 8.0.h()), + child: _submissionType( + title: item['title']!, + time: item['time']!, + isSelected: type == item['value'], + onTap: () { + selectedType = index; + type = item['value']!; + setState(() {}); + }, + ), + ); + }, + ), + SizedBox(height: 8.0.h()), + SizedBox(height: 8.0.h()), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + widget.onConfirm(type); + context.pop(); + const CompletionOfDocumentsRouteData().push(context); + }, + child: Container( + width: double.infinity, + height: 56.0.h(), + decoration: BoxDecoration( + color: AppColors.primary20, + borderRadius: BorderRadius.circular(100), + ), + alignment: Alignment.center, + child: Text( + TenderDetailsStrings.apply, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.mainBlue, + ), + ), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } + + Widget _submissionType({ + required VoidCallback onTap, + required String title, + required String time, + required bool isSelected, + }) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + border: Border.all( + color: isSelected ? AppColors.mainBlue : AppColors.grey40, + ), + ), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: onTap, + child: SizedBox( + width: double.infinity, + height: 40.0.h(), + child: Row( + children: [ + Container( + width: 20.0.w(), + height: 20.0.w(), + margin: EdgeInsets.symmetric( + horizontal: 10.0.w(), + vertical: 10.0.h(), + ), + padding: const EdgeInsets.all(3), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: isSelected ? AppColors.mainBlue : AppColors.grey70, + width: 2.0, + ), + ), + alignment: Alignment.center, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: + isSelected ? AppColors.mainBlue : Colors.transparent, + ), + ), + ), + Expanded( + child: Row( + children: [ + Text( + title, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.grey80, + ), + ), + const Spacer(), + Text( + time, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.grey80, + ), + ), + SizedBox(width: 10.0.w()), + ], + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/views/detail/widgets/show_select_meeting_time_bottom_sheet.dart b/lib/views/detail/widgets/show_select_meeting_time_bottom_sheet.dart deleted file mode 100644 index 3b4dd51..0000000 --- a/lib/views/detail/widgets/show_select_meeting_time_bottom_sheet.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:tm_app/views/detail/widgets/select_meeting_time_bottom_sheet.dart'; - -Future showSelectMeetingTimeDialog({ - required BuildContext context, - required ValueChanged onConfirm, -}) async { - await showDialog( - context: context, - barrierDismissible: true, - builder: (dialogContext) { - return Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - insetPadding: const EdgeInsets.symmetric(horizontal: 32, vertical: 24), - child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 500), - child: SelectMeetingTimeBottomSheet( - isDialog: true, - onConfirm: (value) { - onConfirm(value); - }, - ), - ), - ); - }, - ); -} diff --git a/lib/views/detail/widgets/tender_detail_action.dart b/lib/views/detail/widgets/tender_detail_action.dart index 6cabbbf..b89acc1 100644 --- a/lib/views/detail/widgets/tender_detail_action.dart +++ b/lib/views/detail/widgets/tender_detail_action.dart @@ -3,30 +3,38 @@ import 'package:provider/provider.dart'; import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/view_models/tender_detail_view_model.dart'; -import 'package:tm_app/views/detail/widgets/select_meeting_time_bottom_sheet.dart'; -import 'package:tm_app/views/detail/widgets/show_select_meeting_time_bottom_sheet.dart'; +import 'package:tm_app/views/detail/widgets/meeting_time_bottom_sheet.dart'; +import 'package:tm_app/views/detail/widgets/meeting_time_dialog.dart'; import 'package:tm_app/views/shared/base_button.dart'; import 'package:tm_app/views/shared/select_submission_bottom_sheet.dart'; import '../../../core/constants/tender_approval_status.dart'; import '../../../core/constants/tender_submision_mode.dart'; import '../../../core/routes/app_routes.dart'; +import '../../../core/utils/app_toast.dart'; import '../../../data/services/model/tender_data/tender_data.dart'; import '../../shared/select_submission_dialog.dart'; import '../strings/tender_details_strings.dart'; -class TenderDetailActions extends StatelessWidget { +class TenderDetailActions extends StatefulWidget { final bool isScreenBig; final TenderData detail; + final TenderDetailViewModel viewModel; const TenderDetailActions({ required this.isScreenBig, required this.detail, + required this.viewModel, super.key, }); + @override + State createState() => _TenderDetailActionsState(); +} + +class _TenderDetailActionsState extends State { @override Widget build(BuildContext context) { - return isScreenBig + return widget.isScreenBig ? _webActions() : Column( children: [ @@ -60,25 +68,34 @@ class TenderDetailActions extends StatelessWidget { onConfirm: (String value) { if (value == TenderSubmissionMode.selfApply.value) { - viewModel.submitTenderApproval( - tenderId: detail.id!, - submissionMode: value, + // viewModel.submitTenderApproval( + // tenderId: widget.detail.id!, + // submissionMode: value, + // ); + + const CompletionOfDocumentsRouteData().push( + context, ); } else if (value == TenderSubmissionMode.partnership.value) { Future.delayed(Duration.zero, () { - showDialog( - context: context, - builder: (context) { - return SelectMeetingTimeBottomSheet( - onConfirm: (String value) { - const CompletionOfDocumentsRouteData() - .push(context); - }, - isDialog: false, - ); - }, - ); + if (context.mounted) { + showModalBottomSheet( + context: context, + + builder: (_) { + return MeetingTimeBottomSheet( + onConfirm: (value) { + AppToast.success( + context, + TenderDetailsStrings + .meetingTimeSuccessfullySet, + ); + }, + ); + }, + ); + } }); } }, @@ -112,7 +129,7 @@ class TenderDetailActions extends StatelessWidget { borderWidth: 1, onPressed: () { viewModel.rejectTenderApproval( - tenderId: detail.id!, + tenderId: widget.detail.id!, submissionMode: TenderSubmissionMode.selfApply.value, ); }, @@ -148,7 +165,7 @@ class TenderDetailActions extends StatelessWidget { borderWidth: 1, onPressed: () { viewModel.rejectTenderApproval( - tenderId: detail.id!, + tenderId: widget.detail.id!, submissionMode: TenderSubmissionMode.selfApply.value, ); }, @@ -177,7 +194,7 @@ class TenderDetailActions extends StatelessWidget { if (viewModel.status == TenderApprovalStatus.submitted.value) { viewModel.submitTenderApproval( - tenderId: detail.id!, + tenderId: widget.detail.id!, submissionMode: TenderSubmissionMode.selfApply.value, ); } else { @@ -189,20 +206,29 @@ class TenderDetailActions extends StatelessWidget { onConfirm: (String value) { if (value == TenderSubmissionMode.selfApply.value) { - const FinalCompletionOfDocumentsRouteData() - .push(context); + if (context.mounted) { + const FinalCompletionOfDocumentsRouteData() + .push(context); + } } else if (value == TenderSubmissionMode.partnership.value) { - WidgetsBinding.instance.addPostFrameCallback(( - timeStamp, - ) { - showSelectMeetingTimeDialog( - context: context, - onConfirm: (String value) { - const CompletionOfDocumentsRouteData() - .push(context); - }, - ); + Future.delayed(Duration.zero, () { + if (context.mounted) { + showDialog( + context: context, + builder: (context) { + return MeetingTimeDialog( + onConfirm: (value) { + AppToast.success( + context, + TenderDetailsStrings + .meetingTimeSuccessfullySet, + ); + }, + ); + }, + ); + } }); } }, @@ -216,22 +242,36 @@ class TenderDetailActions extends StatelessWidget { onConfirm: (String value) { if (value == TenderSubmissionMode.selfApply.value) { - viewModel.submitTenderApproval( - tenderId: detail.id!, - submissionMode: value, - ); + // viewModel.submitTenderApproval( + // tenderId: widget.detail.id!, + // submissionMode: value, + // ); + if (context.mounted) { + const FinalCompletionOfDocumentsRouteData() + .push(context); + } } else if (value == TenderSubmissionMode.partnership.value) { showDialog( context: context, builder: (context) { - return SelectMeetingTimeBottomSheet( - onConfirm: (String value) { - const CompletionOfDocumentsRouteData() - .push(context); + return MeetingTimeBottomSheet( + onConfirm: (value) { + AppToast.success( + context, + TenderDetailsStrings + .meetingTimeSuccessfullySet, + ); }, - isDialog: false, ); + // return MeetingTimeDialog( + // onConfirm: (String value) { + // if (context.mounted) { + // const CompletionOfDocumentsRouteData() + // .push(context); + // } + // }, + // ); }, ); } diff --git a/lib/views/final_completion_of_documents/pages/desktop_final_completion_of_documents_page.dart b/lib/views/final_completion_of_documents/pages/desktop_final_completion_of_documents_page.dart index 01423e5..790dd0c 100644 --- a/lib/views/final_completion_of_documents/pages/desktop_final_completion_of_documents_page.dart +++ b/lib/views/final_completion_of_documents/pages/desktop_final_completion_of_documents_page.dart @@ -23,67 +23,62 @@ class DesktopFinalCompletionOfDocumentsPage extends StatelessWidget { return Scaffold( body: Consumer( builder: - (context, viewModel, child) => SafeArea( - child: Column( - children: [ - const DesktopNavigationWidget(currentIndex: 1), - const SizedBox(height: 64.0), - SizedBox( - width: 740, - child: Column( - children: [ - Expanded( - child: SizedBox( - child: SingleChildScrollView( - child: Column( - children: [ - const TabletDesktopAppbar( - title: - FinalCompletionOfDocumentsStrings - .completionOfDocuments, - ), - SizedBox(height: 32.0.h()), + (context, viewModel, child) => Column( + children: [ + const DesktopNavigationWidget(currentIndex: 1), + const SizedBox(height: 42.0), + Expanded( + child: SingleChildScrollView( + child: SizedBox( + width: double.infinity, + child: Center( + child: SizedBox( + width: 740, + child: Column( + children: [ + const TabletDesktopAppbar( + title: + FinalCompletionOfDocumentsStrings + .completionOfDocuments, + ), + SizedBox(height: 32.0.h()), - const SizedBox(height: 32.0), - const CommentBox(), - const SizedBox(height: 32.0), - FormCard(viewModel: viewModel), - const SizedBox(height: 40.0), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - BaseButton( - isEnabled: true, - onPressed: () {}, - width: 176, - backgroundColor: AppColors.primary10, - textColor: AppColors.mainBlue, - text: - FinalCompletionOfDocumentsStrings - .back, - ), - const SizedBox(width: 16.0), - BaseButton( - isEnabled: true, - onPressed: () {}, - width: 176, - text: - FinalCompletionOfDocumentsStrings - .next, - ), - ], + const SizedBox(height: 32.0), + const CommentBox(), + const SizedBox(height: 32.0), + FormCard(viewModel: viewModel), + const SizedBox(height: 40.0), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + BaseButton( + isEnabled: true, + onPressed: () {}, + width: 176, + backgroundColor: AppColors.primary10, + textColor: AppColors.mainBlue, + text: + FinalCompletionOfDocumentsStrings.back, + ), + const SizedBox(width: 16.0), + BaseButton( + isEnabled: true, + onPressed: () {}, + width: 176, + text: + FinalCompletionOfDocumentsStrings.next, ), - const SizedBox(height: 35.0), ], ), - ), + const SizedBox(height: 35.0), + ], ), ), - ], + ), ), ), - ], - ), + ), + ], ), ), );