Files
tm_app/lib/views/detail/widgets/tender_detail_header.dart
T
AmirReza Jamali dde66521f6 Add Docker support and enhance data models for tender details
- Introduced a .dockerignore file to optimize Docker builds by excluding unnecessary files.
- Updated the Dockerfile to use a Flutter base image, enabling web builds for the application.
- Added new data models for `Lot` and `OrganizationAddress` to represent tender details more accurately.
- Enhanced the `Organization` model to include `companyId` and a nested `address` field.
- Updated the `TenderData` model to include new fields such as `noticeTypeCode`, `formType`, and `lots`, reflecting the API response structure.
- Regenerated necessary code for data models to ensure compatibility with the updated structures.
2026-06-03 13:32:42 +03:30

271 lines
8.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/price_extension.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_info_section.dart';
import '../../../core/constants/assets.dart';
import '../../shared/flag.dart';
import '../strings/tender_details_strings.dart';
// AI-NOTE (for PR reviewer): Import is intentionally kept but commented out.
// The static/mock sections it supports (key risks, winning chance, project id,
// service/requirements/background dropdowns) were disabled — NOT removed —
// because they were hard-coded placeholders, not backend data. Re-enable this
// import together with those sections once the API provides that data.
// import 'detail_drop_down.dart';
class TenderDetailHeader extends StatelessWidget {
final bool isScreenBig;
final TenderData detail;
const TenderDetailHeader({
required this.isScreenBig,
required this.detail,
super.key,
});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16.0.w(), vertical: 16.0.h()),
decoration: BoxDecoration(
color: AppColors.backgroundColor,
borderRadius: BorderRadius.circular(12),
border: Border.all(width: 0.5, color: AppColors.grey50),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_titleText(),
SizedBox(height: 4.0.h()),
_nameText(),
SizedBox(height: 4.0.h()),
_idText(),
SizedBox(height: 16.0.h()),
_locationBudgetRow(),
SizedBox(height: 24.0.h()),
// AI-NOTE (for PR reviewer): The following mock sections are disabled
// on purpose (kept for future use). They render hard-coded values, not
// backend data, so they are commented out rather than deleted.
// _projectId(),
// SizedBox(height: 12.0.h()),
// _winningChanceAndDificulty(),
// SizedBox(height: 24.0.h()),
// _keyRisksDropDown(),
// SizedBox(height: 24.0.h()),
Divider(color: AppColors.grey20),
TenderDetailInfoSection(isScreenBig: isScreenBig, detail: detail),
SizedBox(height: 24.0.h()),
_overViewTitle(),
SizedBox(height: 12.0.h()),
_descriptionText(),
// AI-NOTE (for PR reviewer): Mock dropdowns disabled (kept for future).
// _serviceDropDown(),
// SizedBox(height: 24.0.h()),
// _requirementsDropDown(),
// SizedBox(height: 24.0.h()),
// _backgroundDropDown(),
],
),
);
}
Widget _descriptionText() {
return Text(
detail.description ?? '',
style: TextStyle(
color: AppColors.grey70,
fontSize: 16.0.sp(),
fontWeight: FontWeight.w400,
),
);
}
Widget _overViewTitle() {
return Text(
'Overview',
style: TextStyle(
color: AppColors.grey80,
fontSize: 16.0.sp(),
fontWeight: FontWeight.w600,
),
);
}
// AI-NOTE (for PR reviewer): The mock widget builders below are intentionally
// preserved as commented-out code. They produce static placeholder content
// (not backend-driven) and will be reinstated once the API supplies the
// corresponding fields. Do not flag them as dead code — keep as-is.
/*
Widget _serviceDropDown() =>
const DetailDropDown(title: 'Servive/Product', items: []);
Widget _backgroundDropDown() =>
const DetailDropDown(title: 'Background', items: []);
Widget _requirementsDropDown() {
return const DetailDropDown(
title: 'Requirements (Summary)',
items: [
'Market consultation for selecting and procuring a Customer Data Platform (CDP) to unify student data from multiple sources and improve personalization and marketing.',
],
);
}
Widget _keyRisksDropDown() {
return const DetailDropDown(
title: 'Key risks & dealbreakers',
items: [
'ISO 27001:2022 likely mandatory for future tender.',
'Lack of past performance — public sector values references.',
'Implementation & ongoing support required (15 person team expectation).',
],
);
}
Widget _winningChanceAndDificulty() {
return Row(
children: [
Container(
height: 24.0.h(),
padding: EdgeInsets.symmetric(
horizontal: 16.0.w(),
vertical: 4.0.h(),
),
decoration: BoxDecoration(
color: AppColors.blue0,
borderRadius: BorderRadius.circular(8),
),
child: Text(
'Winning chance: <5%',
style: TextStyle(
color: AppColors.blue10,
fontSize: 12.0.sp(),
fontWeight: FontWeight.w500,
),
),
),
SizedBox(width: 12.0.w()),
Container(
height: 24.0.h(),
padding: EdgeInsets.symmetric(
horizontal: 16.0.w(),
vertical: 4.0.h(),
),
decoration: BoxDecoration(
color: AppColors.blue0,
borderRadius: BorderRadius.circular(8),
),
child: Text(
'Difficulty 2/5',
style: TextStyle(
color: AppColors.blue10,
fontSize: 12.0.sp(),
fontWeight: FontWeight.w500,
),
),
),
],
);
}
Widget _projectId() {
return Container(
height: 24.0.h(),
padding: EdgeInsets.symmetric(horizontal: 16.0.w(), vertical: 4.0.h()),
decoration: BoxDecoration(
color: AppColors.blue0,
borderRadius: BorderRadius.circular(8),
),
child: Text(
'Project ID 6243372025NLD',
style: TextStyle(
color: AppColors.blue10,
fontSize: 12.0.sp(),
fontWeight: FontWeight.w500,
),
),
);
}
*/
Widget _locationBudgetRow() {
return Row(
children: [
SvgPicture.asset(
AssetsManager.location,
height: 20.0.h(),
width: 20.0.w(),
),
SizedBox(width: 4.0.w()),
Text(
detail.countryCode ?? '',
style: TextStyle(
color: AppColors.grey70,
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
),
),
SizedBox(width: 8.0.w()),
detail.countryCode != null
? Flag(countryCode: detail.countryCode!)
: const Flag(countryCode: ''),
const Spacer(),
Visibility(
visible: detail.estimatedValue != null && detail.estimatedValue != 0,
child: Container(
height: 32.0.h(),
padding: EdgeInsets.symmetric(horizontal: 16.0.w()),
decoration: BoxDecoration(
color: AppColors.grey30,
borderRadius: BorderRadius.circular(8),
),
alignment: Alignment.center,
child: Text(
'${detail.estimatedValue?.formattedPrice} ${detail.currency ?? ''}',
style: TextStyle(
color: AppColors.grey60,
fontSize: 16.0.sp(),
fontWeight: FontWeight.w600,
),
),
),
),
],
);
}
Widget _idText() {
return Text(
'${TenderDetailsStrings.tenderIdLabel}: ${detail.tenderId}',
style: TextStyle(
color: AppColors.grey80,
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
),
);
}
Widget _nameText() {
return Text(
detail.buyerOrganization?.name ?? '',
style: TextStyle(
color: AppColors.grey80,
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
),
);
}
Widget _titleText() => Text(
detail.title ?? '',
style: TextStyle(
color: AppColors.grey80,
fontWeight: FontWeight.w600,
fontSize: 18.0.sp(),
),
);
}