From 111c332f74fd6603a3482e89c8d2bccebd53a705 Mon Sep 17 00:00:00 2001 From: llsajjad Date: Sat, 9 Aug 2025 07:54:53 +0330 Subject: [PATCH] added 3 screen mod to detail --- lib/core/constants/strings.dart | 34 ++ lib/views/detail/detail_desktop_screen.dart | 67 +++ lib/views/detail/detail_mobile_screen.dart | 62 +++ lib/views/detail/detail_screen.dart | 436 +----------------- lib/views/detail/detail_tablet_screen.dart | 67 +++ lib/views/detail/widgets/deadline_item.dart | 163 +++++++ lib/views/detail/widgets/info_item.dart | 43 ++ lib/views/detail/widgets/status_tag.dart | 34 ++ .../detail/widgets/tender_detail_action.dart | 35 ++ .../detail/widgets/tender_detail_card.dart | 89 ++++ .../detail/widgets/tender_detail_header.dart | 68 +++ .../widgets/tender_detail_info_section.dart | 42 ++ .../widgets/tender_document_section.dart | 29 ++ .../widgets/tender_location_section.dart | 68 +++ 14 files changed, 815 insertions(+), 422 deletions(-) create mode 100644 lib/views/detail/detail_desktop_screen.dart create mode 100644 lib/views/detail/detail_mobile_screen.dart create mode 100644 lib/views/detail/detail_tablet_screen.dart create mode 100644 lib/views/detail/widgets/deadline_item.dart create mode 100644 lib/views/detail/widgets/info_item.dart create mode 100644 lib/views/detail/widgets/status_tag.dart create mode 100644 lib/views/detail/widgets/tender_detail_action.dart create mode 100644 lib/views/detail/widgets/tender_detail_card.dart create mode 100644 lib/views/detail/widgets/tender_detail_header.dart create mode 100644 lib/views/detail/widgets/tender_detail_info_section.dart create mode 100644 lib/views/detail/widgets/tender_document_section.dart create mode 100644 lib/views/detail/widgets/tender_location_section.dart diff --git a/lib/core/constants/strings.dart b/lib/core/constants/strings.dart index 7e4d405..d77e596 100644 --- a/lib/core/constants/strings.dart +++ b/lib/core/constants/strings.dart @@ -41,4 +41,38 @@ class AppStrings { //your tenders static const String yourTendersTitle = 'Your tenders'; + + // Tender Detail Page + static const String tenderDetailTitle = 'Tender Detail'; + static const String tenderStatusOpen = 'Open'; + static const String tenderIdLabel = 'ID'; + static const String tenderDeadlineLabel = 'Deadline'; + static const String tenderApprovalText = 'For approval'; + static const String tenderSubmissionText = 'For submission'; + static const String tenderClientLabel = 'Client'; + static const String tenderDeliveryLocationsLabel = 'Delivery Locations'; + static const String tenderReferenceNumberLabel = 'Reference Number'; + static const String tenderLocationLabel = 'Locations'; + static const String tenderLocationCountry = 'UK'; + static const String tenderPdfDocument = 'PDF , Document'; + static const String tenderMatchProfile = 'Match with your profile'; + static const String tenderIncompleteResume = 'Incomplete Resume Information'; + static const String tenderNoExperience = + 'No experience in e-platform development'; + static const String tenderSubmitButton = 'Submit'; + static const String tenderRejectButton = 'Reject'; + static const String tenderDateExample = '2025-05-21'; +static const String tenderTitleExample = + 'Operation, support and further development of open e-platform Operation, support and further development of open e-platform'; +static const String tenderIdExample = 'JNDFKMDV-100-JF'; +static const String tenderApprovalDateExample = '2025-05-21'; +static const String tenderSubmissionDateExample = '2025-05-21'; +static const String tenderClientExample = + 'Procurement Notice Procurement Notice'; +static const String tenderDeliveryLocationExample = 'Norrbotten County'; +static const String tenderReferenceNumberExample = 'KLF 2025/120'; +static const String tenderDescriptionExample = + 'Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten)...'; +static const String tenderMatchPercentageExample = '75%'; +static const String locationDescription = 'Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten).

The procurement includes operation, support, and further development of the existing open e-platform.

No additional information, amendments, or answers to questions will be provided after June 16.o additional information, amendments, or answers to questions will be provided after June 16.o additional information, amendments, or answers to questions will be provided after June 16.website: www.tenders.com Lorem ipsum is amet Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten).

The procurement includes operation, support, and further development of the existing open e-platform.

No additional information, amendments, or answers to questions will be provided after June 16. o additional information, amendments, or answers to questions will be provided after June 16. o additional information, amendments, or answers to questions will be provided after June 16.website: www.tenders.com'; } diff --git a/lib/views/detail/detail_desktop_screen.dart b/lib/views/detail/detail_desktop_screen.dart new file mode 100644 index 0000000..f054eeb --- /dev/null +++ b/lib/views/detail/detail_desktop_screen.dart @@ -0,0 +1,67 @@ +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/constants/strings.dart'; +import 'package:tm_app/core/utils/size_config.dart'; +import 'package:tm_app/views/detail/widgets/tender_detail_action.dart'; +import 'package:tm_app/views/detail/widgets/tender_detail_card.dart'; +import 'package:tm_app/views/detail/widgets/tender_detail_header.dart'; + +class TenderDetailDesktopScreen extends StatelessWidget { + const TenderDetailDesktopScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: _buildAppBar(context), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Center( + child: SizedBox( + width: 740, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TenderDetailHeader(isBig: true,), + SizedBox(height: 24.0.h()), + const TenderDetailCard(), + SizedBox(height: 24.0.h()), + TenderDetailActions(), + ], + ), + ), + ), + ), + ), + ); + } + + PreferredSizeWidget _buildAppBar(BuildContext context) { + return PreferredSize( + preferredSize: const Size.fromHeight(60), + child: AppBar( + backgroundColor: Colors.white, + elevation: 0, + titleSpacing: 0, + leading: IconButton( + icon: SvgPicture.asset( + AssetsManager.arrowLeft, + height: 24.0.w(), + width: 24.0.w(), + ), + onPressed: () => Navigator.pop(context), + ), + title: Text( + AppStrings.tenderDetailTitle, + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 20.0.sp(), + ), + ), + ), + ); + } +} diff --git a/lib/views/detail/detail_mobile_screen.dart b/lib/views/detail/detail_mobile_screen.dart new file mode 100644 index 0000000..eadc2e8 --- /dev/null +++ b/lib/views/detail/detail_mobile_screen.dart @@ -0,0 +1,62 @@ +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/constants/strings.dart'; +import 'package:tm_app/core/utils/size_config.dart'; +import 'package:tm_app/views/detail/widgets/tender_detail_action.dart'; +import 'package:tm_app/views/detail/widgets/tender_detail_card.dart'; +import 'package:tm_app/views/detail/widgets/tender_detail_header.dart'; + +class TenderDetailMobileScreen extends StatelessWidget { + const TenderDetailMobileScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: _buildAppBar(context), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TenderDetailHeader(isBig: false), + SizedBox(height: 24.0.h()), + const TenderDetailCard(), + SizedBox(height: 24.0.h()), + TenderDetailActions(), + ], + ), + ), + ), + ); + } + + PreferredSizeWidget _buildAppBar(BuildContext context) { + return PreferredSize( + preferredSize: const Size.fromHeight(60), + child: AppBar( + backgroundColor: Colors.white, + elevation: 0, + titleSpacing: 0, + leading: IconButton( + icon: SvgPicture.asset( + AssetsManager.arrowLeft, + height: 24.0.w(), + width: 24.0.w(), + ), + onPressed: () => Navigator.pop(context), + ), + title: Text( + AppStrings.tenderDetailTitle, + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 20.0.sp(), + ), + ), + ), + ); + } +} diff --git a/lib/views/detail/detail_screen.dart b/lib/views/detail/detail_screen.dart index 05ed36f..f51b915 100644 --- a/lib/views/detail/detail_screen.dart +++ b/lib/views/detail/detail_screen.dart @@ -1,432 +1,24 @@ 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/login/widgets/login_button.dart'; +import 'package:tm_app/core/utils/display_size_detector.dart'; +import 'package:tm_app/views/detail/detail_desktop_screen.dart'; +import 'package:tm_app/views/detail/detail_mobile_screen.dart'; +import 'package:tm_app/views/detail/detail_tablet_screen.dart'; class TenderDetailScreen extends StatelessWidget { const TenderDetailScreen({super.key}); @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.white, - appBar: PreferredSize( - preferredSize: const Size.fromHeight(60), - child: AppBar( - backgroundColor: Colors.white, - elevation: 0, - titleSpacing: 0, - leading: IconButton( - icon: SvgPicture.asset( - AssetsManager.arrowLeft, - height: 24.0.w(), - width: 24.0.w(), - ), - onPressed: () => Navigator.pop(context), - ), + final displaySize = MediaQuery.of(context).size.displaySize; - title: const Text( - 'Tender Detail', - style: TextStyle(color: Colors.black, fontWeight: FontWeight.w600), - ), - ), - ), - body: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(5), - border: Border.all(width: 0.5, color: AppColors.grey50), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - '2025-05-21', - style: TextStyle( - color: AppColors.grey60, - fontWeight: FontWeight.w400, - fontSize: 12.0.sp(), - ), - ), - StatusTag( - text: 'Open', - textColor: AppColors.cyanTeal, - backgroundColor: AppColors.cyanAqua, - ), - ], - ), - SizedBox(height: 12.0.h()), - Text( - 'Operation, support and further development of open e-platform Operation, support and further development of open e-platform', - style: TextStyle( - color: AppColors.grey80, - fontWeight: FontWeight.w600, - fontSize: 18.0.sp(), - ), - ), - SizedBox(height: 10.0.h()), - - Divider(), - SizedBox(height: 5.0.h()), - - infoItem('ID', 'JNDFKMDV-100-JF'), - deadlineItem( - title: 'Deadline', - approvalText: 'For approval', - approvalDate: '2025-05-21', - submissionText: 'For submission', - submissionDate: '2025-05-21', - ), - infoItem('Client', 'Procurement Notice Procurement Notice'), - infoItem('Delivery Locations', 'Norrbotten County'), - infoItem('Reference Number', 'KLF 2025/120'), - Padding( - padding: const EdgeInsets.symmetric(vertical: 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 45.0.h(), - child: Text( - 'Reference Number', - style: TextStyle( - color: AppColors.grey80, - fontWeight: FontWeight.w600, - fontSize: 16.0.sp(), - ), - ), - ), - Row( - children: [ - SvgPicture.asset( - AssetsManager.location, - height: 20.0.h(), - width: 20.0.w(), - ), - SizedBox(width: 4.0.w()), - Text( - 'UK', - style: TextStyle( - color: AppColors.grey70, - fontSize: 14.0.sp(), - fontWeight: FontWeight.w400, - ), - ), - SizedBox(width: 4.0.w()), - Image.asset( - AssetsManager.seFlag, - height: 20.0.h(), - width: 20.0.w(), - ), - ], - ), - SizedBox(height: 8.0.h()), - ], - ), - ), - SizedBox(height: 16.0.h()), - Text( - 'Locations', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16.0.sp(), - ), - ), - SizedBox(height: 8.0.h()), - const Text( - 'Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten).\n\n' - 'The procurement includes operation, support, and further development of the existing open e-platform.\n\n' - 'No additional information, amendments, or answers to questions will be provided after June 16.\n\n' - '0 additional information, amendments, or answers to questions will be provided after June 16.\n\n' - '0 additional information, amendments, or answers to questions will be provided after June 16 website: www.tenders.com\n\n' - 'Lorem ipsum is amet\n\n' - 'Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten).\n\n' - 'The procurement includes operation, support, and further development of the existing open e-platform.\n\n' - 'No additional information, amendments, or answers to questions will be provided after June 16.\n\n' - '0 additional information, amendments, or answers to questions will be provided after June 16.\n\n' - '0 additional information, amendments, or answers to questions will be provided after June 16.', - style: TextStyle(height: 1.5), - ), - SizedBox(height: 16.0.h()), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SvgPicture.asset(AssetsManager.export), - SizedBox(height: 6.0.h()), - Text( - 'PDF , Document', - style: TextStyle( - color: Colors.blue, - decoration: TextDecoration.underline, - ), - ), - ], - ), - ], - ), - ), - SizedBox(height: 24.0.h()), - ResumeMatchCard(), - SizedBox(height: 24.0.h()), - Column( - children: [ - BaseButton( - isEnabled: true, - text: 'Submit', - backgroundColor: AppColors.lightBlue, - textColor: AppColors.mainBlue, - onPressed: () {}, - ), - SizedBox(height: 16.0.h()), - BaseButton( - isEnabled: true, - text: 'reject', - borderColor: AppColors.red10, - textColor: AppColors.red10, - backgroundColor: Colors.white, - borderWidth: 1, - onPressed: () {}, - ), - SizedBox(height: 16.0.h()), - ], - ), - ], - ), - ), - ), - ); - } - - Widget deadlineItem({ - required String title, - required String approvalText, - required String approvalDate, - required String submissionText, - required String submissionDate, - }) { - return Padding( - padding: EdgeInsets.symmetric(vertical: 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 45.0.h(), - child: Text( - title, - style: TextStyle( - color: AppColors.grey80, - fontWeight: FontWeight.w600, - fontSize: 16.0.sp(), - ), - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - approvalText, - style: TextStyle( - color: AppColors.grey70, - fontWeight: FontWeight.w400, - fontSize: 14.0.sp(), - ), - ), - Text( - approvalDate, - style: TextStyle( - color: AppColors.grey70, - fontWeight: FontWeight.w400, - fontSize: 14.0.sp(), - ), - ), - ], - ), - SizedBox(height: 4.0.h()), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - submissionText, - style: TextStyle( - color: AppColors.grey70, - fontWeight: FontWeight.w400, - fontSize: 14.0.sp(), - ), - ), - Text( - submissionDate, - style: TextStyle( - color: AppColors.grey70, - fontWeight: FontWeight.w400, - fontSize: 14.0.sp(), - ), - ), - ], - ), - SizedBox(height: 8.0.h()), - Divider(), - ], - ), - ); - } - - Widget infoItem(String title, String value) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 45.0.h(), - child: Text( - title, - style: TextStyle( - color: AppColors.grey80, - fontWeight: FontWeight.w600, - fontSize: 16.0.sp(), - ), - ), - ), - Text( - value, - style: TextStyle( - color: AppColors.grey70, - fontWeight: FontWeight.w400, - fontSize: 14.0.sp(), - ), - ), - SizedBox(height: 8.0.h()), - Divider(), - ], - ), - ); - } -} - -class ResumeMatchCard extends StatelessWidget { - const ResumeMatchCard({super.key}); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: AppColors.paleOrange, - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Match with your profile', - style: TextStyle( - fontSize: 12.0.sp(), - color: Colors.black87, - fontWeight: FontWeight.w400, - ), - ), - Text( - '75%', - style: TextStyle( - fontSize: 12.0.sp(), - fontWeight: FontWeight.w600, - color: AppColors.jellyBean, - ), - ), - ], - ), - SizedBox(height: 6.0.h()), - ClipRRect( - borderRadius: BorderRadius.circular(4), - child: LinearProgressIndicator( - value: 0.75, - backgroundColor: AppColors.grey20, - valueColor: AlwaysStoppedAnimation(AppColors.jellyBean), - minHeight: 6, - ), - ), - SizedBox(height: 16.0.h()), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon(Icons.warning_rounded, color: Colors.red), - SizedBox(width: 8.0.w()), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Incomplete Resume Information', - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0.sp(), - color: Colors.black87, - ), - ), - SizedBox(height: 4.0.h()), - Text( - 'No experience in e-platform development', - style: TextStyle( - fontSize: 14.0.sp(), - color: Colors.black54, - fontWeight: FontWeight.w400, - ), - ), - ], - ), - ), - ], - ), - ], - ), - ); - } -} - -class StatusTag extends StatelessWidget { - final String text; - final Color textColor; - final Color backgroundColor; - - const StatusTag({ - required this.text, - required this.textColor, - required this.backgroundColor, - super.key, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.symmetric(horizontal: 12.0.w(), vertical: 6.0.h()), - decoration: BoxDecoration( - color: backgroundColor, - borderRadius: BorderRadius.circular(8), - ), - child: Text( - text, - style: TextStyle( - color: textColor, - fontWeight: FontWeight.w500, - fontSize: 14.0.sp(), - ), - ), - ); + switch (displaySize) { + case DisplaySize.large: + case DisplaySize.medium: + return const TenderDetailDesktopScreen(); + case DisplaySize.small: + return const TenderDetailTabletScreen(); + case DisplaySize.extraSmall: + return const TenderDetailMobileScreen(); + } } } diff --git a/lib/views/detail/detail_tablet_screen.dart b/lib/views/detail/detail_tablet_screen.dart new file mode 100644 index 0000000..03df0c8 --- /dev/null +++ b/lib/views/detail/detail_tablet_screen.dart @@ -0,0 +1,67 @@ +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/constants/strings.dart'; +import 'package:tm_app/core/utils/size_config.dart'; +import 'package:tm_app/views/detail/widgets/tender_detail_action.dart'; +import 'package:tm_app/views/detail/widgets/tender_detail_card.dart'; +import 'package:tm_app/views/detail/widgets/tender_detail_header.dart'; + +class TenderDetailTabletScreen extends StatelessWidget { + const TenderDetailTabletScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: _buildAppBar(context), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Center( + child: SizedBox( + width: 768, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TenderDetailHeader(isBig: true,), + SizedBox(height: 24.0.h()), + const TenderDetailCard(), + SizedBox(height: 24.0.h()), + TenderDetailActions(), + ], + ), + ), + ), + ), + ), + ); + } + + PreferredSizeWidget _buildAppBar(BuildContext context) { + return PreferredSize( + preferredSize: const Size.fromHeight(60), + child: AppBar( + backgroundColor: Colors.white, + elevation: 0, + titleSpacing: 0, + leading: IconButton( + icon: SvgPicture.asset( + AssetsManager.arrowLeft, + height: 24.0.w(), + width: 24.0.w(), + ), + onPressed: () => Navigator.pop(context), + ), + title: Text( + AppStrings.tenderDetailTitle, + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 20.0.sp(), + ), + ), + ), + ); + } +} diff --git a/lib/views/detail/widgets/deadline_item.dart b/lib/views/detail/widgets/deadline_item.dart new file mode 100644 index 0000000..81ffba5 --- /dev/null +++ b/lib/views/detail/widgets/deadline_item.dart @@ -0,0 +1,163 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/core/theme/colors.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +class DeadlineItem extends StatelessWidget { + final String title; + final String approvalText; + final String approvalDate; + final String submissionText; + final String submissionDate; + final bool isBig; + + const DeadlineItem({ + required this.title, required this.approvalText, required this.approvalDate, required this.submissionText, required this.submissionDate, required this.isBig, super.key, + }); + + @override + Widget build(BuildContext context) { + return isBig ? Padding( + padding: EdgeInsets.symmetric(vertical: 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 45.0.h(), + child: Text( + title, + style: TextStyle( + color: AppColors.grey80, + fontWeight: FontWeight.w600, + fontSize: 16.0.sp(), + ), + ), + ), + IntrinsicHeight( + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + approvalText, + style: TextStyle( + color: AppColors.grey70, + fontWeight: FontWeight.w400, + fontSize: 14.0.sp(), + ), + ), + SizedBox(height: 4.0.h()), + Text( + approvalDate, + style: TextStyle( + color: AppColors.grey80, + fontWeight: FontWeight.w400, + fontSize: 14.0.sp(), + ), + ), + ], + ), + ), + VerticalDivider( + color: AppColors.grey30, + thickness: 1, + width: 24, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + submissionText, + style: TextStyle( + color: AppColors.grey70, + fontWeight: FontWeight.w400, + fontSize: 14.0.sp(), + ), + ), + SizedBox(height: 4.0.h()), + Text( + submissionDate, + style: TextStyle( + color: AppColors.grey80, + fontWeight: FontWeight.w400, + fontSize: 14.0.sp(), + ), + ), + ], + ), + ), + ], + ), + ), + SizedBox(height: 8.0.h()), + const Divider(), + ], + ), + ) : Padding( + padding: EdgeInsets.symmetric(vertical: 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 45.0.h(), + child: Text( + title, + style: TextStyle( + color: AppColors.grey80, + fontWeight: FontWeight.w600, + fontSize: 16.0.sp(), + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + approvalText, + style: TextStyle( + color: AppColors.grey70, + fontWeight: FontWeight.w400, + fontSize: 14.0.sp(), + ), + ), + Text( + approvalDate, + style: TextStyle( + color: AppColors.grey70, + fontWeight: FontWeight.w400, + fontSize: 14.0.sp(), + ), + ), + ], + ), + SizedBox(height: 4.0.h()), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + submissionText, + style: TextStyle( + color: AppColors.grey70, + fontWeight: FontWeight.w400, + fontSize: 14.0.sp(), + ), + ), + Text( + submissionDate, + style: TextStyle( + color: AppColors.grey70, + fontWeight: FontWeight.w400, + fontSize: 14.0.sp(), + ), + ), + ], + ), + SizedBox(height: 8.0.h()), + const Divider(), + ], + ), + ); + } +} diff --git a/lib/views/detail/widgets/info_item.dart b/lib/views/detail/widgets/info_item.dart new file mode 100644 index 0000000..21c326b --- /dev/null +++ b/lib/views/detail/widgets/info_item.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/core/theme/colors.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +class InfoItem extends StatelessWidget { + const InfoItem({required this.title, required this.value, super.key}); + + final String title; + final String value; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 45.0.h(), + child: Text( + title, + style: TextStyle( + color: AppColors.grey80, + fontWeight: FontWeight.w600, + fontSize: 16.0.sp(), + ), + ), + ), + Text( + value, + style: TextStyle( + color: AppColors.grey70, + fontWeight: FontWeight.w400, + fontSize: 14.0.sp(), + ), + ), + SizedBox(height: 8.0.h()), + const Divider(), + ], + ), + ); + } +} diff --git a/lib/views/detail/widgets/status_tag.dart b/lib/views/detail/widgets/status_tag.dart new file mode 100644 index 0000000..ea199fa --- /dev/null +++ b/lib/views/detail/widgets/status_tag.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +class StatusTag extends StatelessWidget { + final String text; + final Color textColor; + final Color backgroundColor; + + const StatusTag({ + required this.text, + required this.textColor, + required this.backgroundColor, + super.key, + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 12.0.w(), vertical: 6.0.h()), + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(8), + ), + child: Text( + text, + style: TextStyle( + color: textColor, + fontWeight: FontWeight.w500, + fontSize: 14.0.sp(), + ), + ), + ); + } +} diff --git a/lib/views/detail/widgets/tender_detail_action.dart b/lib/views/detail/widgets/tender_detail_action.dart new file mode 100644 index 0000000..0019d01 --- /dev/null +++ b/lib/views/detail/widgets/tender_detail_action.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/core/constants/strings.dart'; +import 'package:tm_app/core/theme/colors.dart'; +import 'package:tm_app/core/utils/size_config.dart'; +import 'package:tm_app/views/login/widgets/login_button.dart'; + +class TenderDetailActions extends StatelessWidget { + const TenderDetailActions({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + BaseButton( + isEnabled: true, + text: AppStrings.tenderSubmitButton, + backgroundColor: AppColors.lightBlue, + textColor: AppColors.mainBlue, + onPressed: () {}, + ), + SizedBox(height: 16.0.h()), + BaseButton( + isEnabled: true, + text: AppStrings.tenderRejectButton, + borderColor: AppColors.red10, + textColor: AppColors.red10, + backgroundColor: Colors.white, + borderWidth: 1, + onPressed: () {}, + ), + SizedBox(height: 16.0.h()), + ], + ); + } +} diff --git a/lib/views/detail/widgets/tender_detail_card.dart b/lib/views/detail/widgets/tender_detail_card.dart new file mode 100644 index 0000000..4b59081 --- /dev/null +++ b/lib/views/detail/widgets/tender_detail_card.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/core/constants/strings.dart'; +import 'package:tm_app/core/theme/colors.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +class TenderDetailCard extends StatelessWidget { + const TenderDetailCard({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColors.paleOrange, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + AppStrings.tenderMatchProfile, + style: TextStyle( + fontSize: 12.0, + color: Colors.black87, + fontWeight: FontWeight.w400, + ), + ), + Text( + AppStrings.tenderMatchPercentageExample, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.jellyBean, + ), + ), + ], + ), + SizedBox(height: 6.0.h()), + + ClipRRect( + borderRadius: BorderRadius.circular(4), + child: LinearProgressIndicator( + value: 0.75, + backgroundColor: AppColors.grey20, + valueColor: AlwaysStoppedAnimation(AppColors.jellyBean), + minHeight: 6, + ), + ), + SizedBox(height: 16.0.h()), + + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.warning_rounded, color: Colors.red), + SizedBox(width: 8.0.w()), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [ + Text( + AppStrings.tenderIncompleteResume, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16.0, + color: Colors.black87, + ), + ), + SizedBox(height: 4.0), + Text( + AppStrings.tenderNoExperience, + style: TextStyle( + fontSize: 14.0, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + ], + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/detail/widgets/tender_detail_header.dart b/lib/views/detail/widgets/tender_detail_header.dart new file mode 100644 index 0000000..1d814d1 --- /dev/null +++ b/lib/views/detail/widgets/tender_detail_header.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/core/constants/strings.dart'; +import 'package:tm_app/core/theme/colors.dart'; +import 'package:tm_app/core/utils/size_config.dart'; +import 'package:tm_app/views/detail/widgets/status_tag.dart'; +import 'package:tm_app/views/detail/widgets/tender_detail_info_section.dart'; +import 'package:tm_app/views/detail/widgets/tender_document_section.dart'; +import 'package:tm_app/views/detail/widgets/tender_location_section.dart'; + +class TenderDetailHeader extends StatelessWidget { + final bool isBig; + const TenderDetailHeader({required this.isBig, super.key}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + border: Border.all(width: 0.5, color: AppColors.grey50), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildDateAndStatus(), + SizedBox(height: 12.0.h()), + _buildTitle(), + SizedBox(height: 10.0.h()), + const Divider(), + SizedBox(height: 5.0.h()), + TenderDetailInfoSection(isBig: isBig,), + TenderLocationSection(), + SizedBox(height: 16.0.h()), + TenderDocumentSection(), + ], + ), + ); + } + + Widget _buildDateAndStatus() => Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + AppStrings.tenderDateExample, + style: TextStyle( + color: AppColors.grey60, + fontWeight: FontWeight.w400, + fontSize: 12.0.sp(), + ), + ), + const StatusTag( + text: AppStrings.tenderStatusOpen, + textColor: AppColors.cyanTeal, + backgroundColor: AppColors.cyanAqua, + ), + ], + ); + + Widget _buildTitle() => Text( + AppStrings.tenderTitleExample, + style: TextStyle( + color: AppColors.grey80, + fontWeight: FontWeight.w600, + fontSize: 18.0.sp(), + ), + ); +} diff --git a/lib/views/detail/widgets/tender_detail_info_section.dart b/lib/views/detail/widgets/tender_detail_info_section.dart new file mode 100644 index 0000000..eaac5d5 --- /dev/null +++ b/lib/views/detail/widgets/tender_detail_info_section.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/core/constants/strings.dart'; +import 'package:tm_app/views/detail/widgets/deadline_item.dart'; +import 'package:tm_app/views/detail/widgets/info_item.dart'; + +class TenderDetailInfoSection extends StatelessWidget { + final bool isBig; + + const TenderDetailInfoSection({required this.isBig ,super.key}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InfoItem( + title: AppStrings.tenderIdLabel, + value: AppStrings.tenderIdExample, + ), + DeadlineItem( + title: AppStrings.tenderDeadlineLabel, + approvalText: AppStrings.tenderApprovalText, + approvalDate: AppStrings.tenderApprovalDateExample, + submissionText: AppStrings.tenderSubmissionText, + submissionDate: AppStrings.tenderSubmissionDateExample, isBig: isBig, + ), + InfoItem( + title: AppStrings.tenderClientLabel, + value: AppStrings.tenderClientExample, + ), + InfoItem( + title: AppStrings.tenderDeliveryLocationsLabel, + value: AppStrings.tenderDeliveryLocationExample, + ), + InfoItem( + title: AppStrings.tenderReferenceNumberLabel, + value: AppStrings.tenderReferenceNumberExample, + ), + ], + ); + } +} diff --git a/lib/views/detail/widgets/tender_document_section.dart b/lib/views/detail/widgets/tender_document_section.dart new file mode 100644 index 0000000..f2e59aa --- /dev/null +++ b/lib/views/detail/widgets/tender_document_section.dart @@ -0,0 +1,29 @@ +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/constants/strings.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +class TenderDocumentSection extends StatelessWidget { + const TenderDocumentSection({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset(AssetsManager.export), + SizedBox(height: 6.0.h()), + Text( + AppStrings.tenderPdfDocument, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 16.0.sp(), + color: Colors.blue, + decoration: TextDecoration.underline, + ), + ), + ], + ); + } +} diff --git a/lib/views/detail/widgets/tender_location_section.dart b/lib/views/detail/widgets/tender_location_section.dart new file mode 100644 index 0000000..d652767 --- /dev/null +++ b/lib/views/detail/widgets/tender_location_section.dart @@ -0,0 +1,68 @@ +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/constants/strings.dart'; +import 'package:tm_app/core/theme/colors.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +class TenderLocationSection extends StatelessWidget { + const TenderLocationSection({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 45.0.h(), + child: Text( + AppStrings.tenderReferenceNumberLabel, + style: TextStyle( + color: AppColors.grey80, + fontWeight: FontWeight.w600, + fontSize: 16.0.sp(), + ), + ), + ), + Row( + children: [ + SvgPicture.asset( + AssetsManager.location, + height: 20.0.h(), + width: 20.0.w(), + ), + SizedBox(width: 4.0.w()), + Text( + AppStrings.tenderLocationCountry, + style: TextStyle( + color: AppColors.grey70, + fontSize: 14.0.sp(), + fontWeight: FontWeight.w400, + ), + ), + SizedBox(width: 4.0.w()), + Image.asset( + AssetsManager.seFlag, + height: 20.0.h(), + width: 20.0.w(), + ), + ], + ), + SizedBox(height: 8.0.h()), + Text( + AppStrings.tenderLocationLabel, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0.sp()), + ), + SizedBox(height: 8.0.h()), + Text( + AppStrings.locationDescription, + style: TextStyle(fontWeight: FontWeight.w400, fontSize: 14.0.sp()), + ), + SizedBox(height: 16.0.h()), + ], + ), + ); + } +}