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 82431f6..334439c 100644 --- a/lib/core/routes/app_routes.dart +++ b/lib/core/routes/app_routes.dart @@ -2,7 +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/m_completion_of_documents_page.dart'; +import 'package:tm_app/views/completion_of_documents/pages/complectopn_of_documents_screen.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,6 +236,17 @@ 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(); @@ -246,20 +257,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 b4d8ecb..b1430a1 100644 --- a/lib/core/routes/app_routes.g.dart +++ b/lib/core/routes/app_routes.g.dart @@ -12,8 +12,8 @@ List get $appRoutes => [ $appShellRouteData, $yourTendersRouteData, $finalCompletionOfDocumentsRouteData, + $completionOfDocumentsRouteData, $likedTendersRouteData, - $completionOfDocumentsMobileRouteData, $tenderDetailRouteData, $forgotPasswordRouteData, $forgotPasswordOtpRouteData, @@ -299,18 +299,18 @@ mixin _$FinalCompletionOfDocumentsRouteData on GoRouteData { void replace(BuildContext context) => context.replace(location); } -RouteBase get $likedTendersRouteData => GoRouteData.$route( - path: '/like-tenders', +RouteBase get $completionOfDocumentsRouteData => GoRouteData.$route( + path: '/completion_of_documents', - factory: _$LikedTendersRouteData._fromState, + factory: _$CompletionOfDocumentsRouteData._fromState, ); -mixin _$LikedTendersRouteData on GoRouteData { - static LikedTendersRouteData _fromState(GoRouterState state) => - const LikedTendersRouteData(); +mixin _$CompletionOfDocumentsRouteData on GoRouteData { + static CompletionOfDocumentsRouteData _fromState(GoRouterState state) => + const CompletionOfDocumentsRouteData(); @override - String get location => GoRouteData.$location('/like-tenders'); + String get location => GoRouteData.$location('/completion_of_documents'); @override void go(BuildContext context) => context.go(location); @@ -326,18 +326,18 @@ mixin _$LikedTendersRouteData on GoRouteData { void replace(BuildContext context) => context.replace(location); } -RouteBase get $completionOfDocumentsMobileRouteData => GoRouteData.$route( - path: '/completion-of-documents', +RouteBase get $likedTendersRouteData => GoRouteData.$route( + path: '/like-tenders', - factory: _$CompletionOfDocumentsMobileRouteData._fromState, + factory: _$LikedTendersRouteData._fromState, ); -mixin _$CompletionOfDocumentsMobileRouteData on GoRouteData { - static CompletionOfDocumentsMobileRouteData _fromState(GoRouterState state) => - const CompletionOfDocumentsMobileRouteData(); +mixin _$LikedTendersRouteData on GoRouteData { + static LikedTendersRouteData _fromState(GoRouterState state) => + const LikedTendersRouteData(); @override - String get location => GoRouteData.$location('/completion-of-documents'); + String get location => GoRouteData.$location('/like-tenders'); @override void go(BuildContext context) => context.go(location); diff --git a/lib/view_models/tender_detail_view_model.dart b/lib/view_models/tender_detail_view_model.dart index 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/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..6f82ce5 --- /dev/null +++ b/lib/views/completion_of_documents/pages/d_completion_of_documents_page.dart @@ -0,0 +1,381 @@ +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'; +import 'package:tm_app/views/shared/tablet_desktop_appbar.dart' + show TabletDesktopAppbar; + +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), + Expanded( + child: SingleChildScrollView( + child: SizedBox( + width: double.infinity, + child: Center( + child: SizedBox( + width: 760, + child: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 40.0.h()), + const TabletDesktopAppbar( + title: + CompletionOfDocumentsStrings + .completionOfDocuments, + ), + + 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, + ), + SizedBox(height: 24.0.h()), + ], + ), + ), + ), + ), + ), + ), + ), + ], + ), + ); + } + + 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..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 @@ -5,7 +5,8 @@ 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'; + +import '../../shared/tender_app_bar.dart'; class CompletionOfDocumentsMobilePage extends StatelessWidget { const CompletionOfDocumentsMobilePage({super.key}); 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/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 61% rename from lib/views/detail/widgets/select_meeting_time_bottom_sheet.dart rename to lib/views/detail/widgets/meeting_time_bottom_sheet.dart index e5c3394..953f8b6 100644 --- a/lib/views/detail/widgets/select_meeting_time_bottom_sheet.dart +++ b/lib/views/detail/widgets/meeting_time_bottom_sheet.dart @@ -1,20 +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, 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; @override - State createState() => - _SelectMeetingTimeBottomSheetState(); + State createState() => _MeetingTimeBottomSheetState(); } -class _SelectMeetingTimeBottomSheetState - extends State { +class _MeetingTimeBottomSheetState extends State { int selectedType = 0; late String type = ''; @@ -25,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( @@ -76,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, @@ -117,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/tender_detail_action.dart b/lib/views/detail/widgets/tender_detail_action.dart index 1d04aa8..b89acc1 100644 --- a/lib/views/detail/widgets/tender_detail_action.dart +++ b/lib/views/detail/widgets/tender_detail_action.dart @@ -3,29 +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/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: [ @@ -53,31 +62,40 @@ 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: widget.detail.id!, + // submissionMode: value, + // ); + + const CompletionOfDocumentsRouteData().push( + context, + ); + } else if (value == + TenderSubmissionMode.partnership.value) { Future.delayed(Duration.zero, () { - showModalBottomSheet( - isDismissible: true, - // ignore: use_build_context_synchronously - context: context, - builder: (context) { - return SelectMeetingTimeBottomSheet( - onConfirm: (meetingTime) {}, - ); - }, - ); + if (context.mounted) { + showModalBottomSheet( + context: context, + + builder: (_) { + return MeetingTimeBottomSheet( + onConfirm: (value) { + AppToast.success( + context, + TenderDetailsStrings + .meetingTimeSuccessfullySet, + ); + }, + ); + }, + ); + } }); } }, @@ -111,7 +129,7 @@ class TenderDetailActions extends StatelessWidget { borderWidth: 1, onPressed: () { viewModel.rejectTenderApproval( - tenderId: detail.id!, + tenderId: widget.detail.id!, submissionMode: TenderSubmissionMode.selfApply.value, ); }, @@ -147,7 +165,7 @@ class TenderDetailActions extends StatelessWidget { borderWidth: 1, onPressed: () { viewModel.rejectTenderApproval( - tenderId: detail.id!, + tenderId: widget.detail.id!, submissionMode: TenderSubmissionMode.selfApply.value, ); }, @@ -176,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 { @@ -186,10 +204,33 @@ class TenderDetailActions extends StatelessWidget { builder: (context) { return SelectSubmissionDialog( onConfirm: (String value) { - viewModel.submitTenderApproval( - tenderId: detail.id!, - submissionMode: value, - ); + if (value == + TenderSubmissionMode.selfApply.value) { + if (context.mounted) { + const FinalCompletionOfDocumentsRouteData() + .push(context); + } + } else if (value == + TenderSubmissionMode.partnership.value) { + Future.delayed(Duration.zero, () { + if (context.mounted) { + showDialog( + context: context, + builder: (context) { + return MeetingTimeDialog( + onConfirm: (value) { + AppToast.success( + context, + TenderDetailsStrings + .meetingTimeSuccessfullySet, + ); + }, + ); + }, + ); + } + }); + } }, ); }, @@ -199,10 +240,41 @@ 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: widget.detail.id!, + // submissionMode: value, + // ); + if (context.mounted) { + const FinalCompletionOfDocumentsRouteData() + .push(context); + } + } else if (value == + TenderSubmissionMode.partnership.value) { + showDialog( + context: context, + builder: (context) { + return MeetingTimeBottomSheet( + onConfirm: (value) { + AppToast.success( + context, + TenderDetailsStrings + .meetingTimeSuccessfullySet, + ); + }, + ); + // 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 new file mode 100644 index 0000000..790dd0c --- /dev/null +++ b/lib/views/final_completion_of_documents/pages/desktop_final_completion_of_documents_page.dart @@ -0,0 +1,321 @@ +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) => 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: 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, + ), + ), + ), + ), + ], ), ), ],