From 4b51071aad5fc844c44fff461f50a67a99f94b6c Mon Sep 17 00:00:00 2001 From: amirrezaghabeli Date: Wed, 20 Aug 2025 13:11:22 +0330 Subject: [PATCH] merge branches --- assets/icons/moon.svg | 3 + assets/icons/sun.svg | 4 + lib/core/config/dependencies.dart | 6 +- lib/core/constants/assets.dart | 7 +- lib/core/constants/strings.dart | 2 + lib/core/network/network_manager.dart | 12 +- lib/core/theme/colors.dart | 3 + lib/data/repositories/tenders_repository.dart | 21 ++ .../tender_approvals_by_id_response.dart | 22 ++ ...nder_approvals_by_id_response.freezed.dart | 334 ++++++++++++++++++ .../tender_approvals_by_id_response.g.dart | 31 ++ .../tender_approvals_data.dart | 27 ++ .../tender_approvals_response.dart | 25 ++ .../tender_approvals_toggle_data.dart | 21 ++ .../tender_approvals_toggle_data.freezed.dart | 292 +++++++++++++++ .../tender_approvals_toggle_data.g.dart | 29 ++ .../tender_approvals_toggle_response.dart | 21 ++ ...der_approvals_toggle_response.freezed.dart | 334 ++++++++++++++++++ .../tender_approvals_toggle_response.g.dart | 33 ++ lib/data/services/tenders_service.dart | 32 ++ lib/gen/assets.gen.dart | 8 + lib/view_models/auth_view_model.dart | 7 - lib/view_models/profile_view_model.dart | 39 +- lib/view_models/tender_detail_view_model.dart | 66 +++- lib/view_models/tenders_view_model.dart | 116 ++++++ .../detail/pages/detail_desktop_page.dart | 2 +- .../detail/pages/detail_mobile_page.dart | 2 +- .../detail/pages/detail_tablet_page.dart | 2 +- .../detail/widgets/tender_detail_action.dart | 87 ++++- lib/views/home/tenders_list_item.dart | 2 +- lib/views/profile/pages/m_profile_page.dart | 75 ++-- lib/views/profile/widgets/theme_toggle.dart | 26 +- .../select_submission_bottom_sheet.dart | 145 ++++++++ .../tenders/widgets/main_tenders_slider.dart | 55 +-- .../widgets/tender_action_buttons_row.dart | 94 +++-- lib/views/tenders/widgets/tender_card.dart | 76 +++- 36 files changed, 1894 insertions(+), 167 deletions(-) create mode 100644 assets/icons/moon.svg create mode 100644 assets/icons/sun.svg create mode 100644 lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart create mode 100644 lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.freezed.dart create mode 100644 lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.g.dart create mode 100644 lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.dart create mode 100644 lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.freezed.dart create mode 100644 lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.g.dart create mode 100644 lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart create mode 100644 lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.freezed.dart create mode 100644 lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.g.dart create mode 100644 lib/views/shared/select_submission_bottom_sheet.dart diff --git a/assets/icons/moon.svg b/assets/icons/moon.svg new file mode 100644 index 0000000..7757b12 --- /dev/null +++ b/assets/icons/moon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/sun.svg b/assets/icons/sun.svg new file mode 100644 index 0000000..bca45f7 --- /dev/null +++ b/assets/icons/sun.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/core/config/dependencies.dart b/lib/core/config/dependencies.dart index 53c57b9..fe6daef 100644 --- a/lib/core/config/dependencies.dart +++ b/lib/core/config/dependencies.dart @@ -84,8 +84,10 @@ List get viewModels { ), ChangeNotifierProvider( create: - (context) => - TenderDetailViewModel(tenderDetailRepository: context.read()), + (context) => TenderDetailViewModel( + tenderDetailRepository: context.read(), + tendersRepository: context.read(), + ), ), ChangeNotifierProvider( diff --git a/lib/core/constants/assets.dart b/lib/core/constants/assets.dart index 76b941b..02e8bcf 100644 --- a/lib/core/constants/assets.dart +++ b/lib/core/constants/assets.dart @@ -15,7 +15,8 @@ class AssetsManager { static const userIcon = 'assets/svgs/user_icon.svg'; static const passwordIcon = 'assets/svgs/password_icon.svg'; static const passwordVisibility = 'assets/svgs/password_visibility.svg'; - static const passwordVisibilityOff = 'assets/svgs/password_visibility_off.svg'; + static const passwordVisibilityOff = + 'assets/svgs/password_visibility_off.svg'; // tenders page static const tenderLogo = 'assets/icons/tenderLogo.png'; @@ -44,4 +45,8 @@ class AssetsManager { static const tickCircle = 'assets/icons/tick-circle.svg'; static const arrowLeft = 'assets/svgs/arrow_left.svg'; static const export = 'assets/svgs/export.svg'; + + //profile page + static const sun = 'assets/icons/sun.svg'; + static const moon = 'assets/icons/moon.svg'; } diff --git a/lib/core/constants/strings.dart b/lib/core/constants/strings.dart index 5bd901e..c5a735e 100644 --- a/lib/core/constants/strings.dart +++ b/lib/core/constants/strings.dart @@ -47,6 +47,8 @@ class AppStrings { //profile static const String profile = 'Profile'; + static const String settings = 'Settings'; + static const String appTheme = 'App Theme'; //your tenders static const String yourTendersTitle = 'Your tenders'; diff --git a/lib/core/network/network_manager.dart b/lib/core/network/network_manager.dart index 26b5498..c380497 100644 --- a/lib/core/network/network_manager.dart +++ b/lib/core/network/network_manager.dart @@ -11,6 +11,7 @@ import 'network_connectivity.dart'; class NetworkManager { final Dio mainDio; final NetworkConnectivity _connectivity = NetworkConnectivity(); + bool _interceptorsAdded = false; NetworkManager() : mainDio = Dio( @@ -21,9 +22,13 @@ class NetworkManager { 'Content-Type': 'application/json', }, ), - ); + ) { + _addInterceptors(); + } + + void _addInterceptors() { + if (_interceptorsAdded) return; - Future addInterceptors() async { final requestInterceptor = InterceptorsWrapper( onRequest: (options, handler) { appLogger.info('🌐 Request: ${options.method} ${options.path}'); @@ -47,6 +52,7 @@ class NetworkManager { ); mainDio.interceptors.add(requestInterceptor); + _interceptorsAdded = true; } /// Enhanced makeRequest method with comprehensive error handling @@ -71,8 +77,6 @@ class NetworkManager { SharedPreferences prefs = await SharedPreferences.getInstance(); Dio dioInstance = mainDio; - await addInterceptors(); - Future makeApiCall(String token) async { final headers = token.isEmpty diff --git a/lib/core/theme/colors.dart b/lib/core/theme/colors.dart index aafb720..4407c30 100644 --- a/lib/core/theme/colors.dart +++ b/lib/core/theme/colors.dart @@ -137,6 +137,9 @@ class AppColors { static Color get blue0 => _isDarkMode ? const Color(0xFF4C6367) : const Color(0xFFD6F4F8); + static Color get error => + _isDarkMode ? const Color(0xFFFF3232) : const Color(0xFFC02525); + static Color get red0 => _isDarkMode ? const Color(0xFF312F2F) diff --git a/lib/data/repositories/tenders_repository.dart b/lib/data/repositories/tenders_repository.dart index 6d6f5bd..8d991ad 100644 --- a/lib/data/repositories/tenders_repository.dart +++ b/lib/data/repositories/tenders_repository.dart @@ -1,8 +1,11 @@ import 'package:tm_app/core/utils/result.dart'; import 'package:tm_app/data/services/model/feedback_response/feedback_response.dart'; +import 'package:tm_app/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart'; import 'package:tm_app/data/services/model/tenders/tenders_response/tenders_response.dart'; import 'package:tm_app/data/services/tenders_service.dart'; +import '../services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart'; + class TendersRepository { TendersRepository({required TendersService tendersService}) : _tendersService = tendersService; @@ -30,4 +33,22 @@ class TendersRepository { feedbackType: feedbackType, ); } + + Future> toggleApprovals({ + required String tenderId, + required String submissionMode, + required String status, + }) async { + return _tendersService.toggleApprovals( + tenderId: tenderId, + submissionMode: submissionMode, + status: status, + ); + } + + Future> getTenderApprovals({ + required String tenderId, + }) async { + return _tendersService.getTenderApprovalsById(tenderId: tenderId); + } } diff --git a/lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart b/lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart new file mode 100644 index 0000000..6539b92 --- /dev/null +++ b/lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart @@ -0,0 +1,22 @@ +// ignore_for_file: invalid_annotation_target + +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../error/error_model.dart'; +import '../tender_approvals_data/tender_approvals_data.dart'; + +part 'tender_approvals_by_id_response.freezed.dart'; +part 'tender_approvals_by_id_response.g.dart'; + +@freezed +abstract class TenderApprovalsByIdResponse with _$TenderApprovalsByIdResponse { + const factory TenderApprovalsByIdResponse({ + required String? message, + required bool? success, + required ErrorModel? error, + required TenderApprovalsData? data, + }) = _TenderApprovalsByIdResponse; + + factory TenderApprovalsByIdResponse.fromJson(Map json) => + _$TenderApprovalsByIdResponseFromJson(json); +} diff --git a/lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.freezed.dart b/lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.freezed.dart new file mode 100644 index 0000000..9b0a73a --- /dev/null +++ b/lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.freezed.dart @@ -0,0 +1,334 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'tender_approvals_by_id_response.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$TenderApprovalsByIdResponse { + + String? get message; bool? get success; ErrorModel? get error; TenderApprovalsData? get data; +/// Create a copy of TenderApprovalsByIdResponse +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$TenderApprovalsByIdResponseCopyWith get copyWith => _$TenderApprovalsByIdResponseCopyWithImpl(this as TenderApprovalsByIdResponse, _$identity); + + /// Serializes this TenderApprovalsByIdResponse to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is TenderApprovalsByIdResponse&&(identical(other.message, message) || other.message == message)&&(identical(other.success, success) || other.success == success)&&(identical(other.error, error) || other.error == error)&&(identical(other.data, data) || other.data == data)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,message,success,error,data); + +@override +String toString() { + return 'TenderApprovalsByIdResponse(message: $message, success: $success, error: $error, data: $data)'; +} + + +} + +/// @nodoc +abstract mixin class $TenderApprovalsByIdResponseCopyWith<$Res> { + factory $TenderApprovalsByIdResponseCopyWith(TenderApprovalsByIdResponse value, $Res Function(TenderApprovalsByIdResponse) _then) = _$TenderApprovalsByIdResponseCopyWithImpl; +@useResult +$Res call({ + String? message, bool? success, ErrorModel? error, TenderApprovalsData? data +}); + + +$ErrorModelCopyWith<$Res>? get error;$TenderApprovalsDataCopyWith<$Res>? get data; + +} +/// @nodoc +class _$TenderApprovalsByIdResponseCopyWithImpl<$Res> + implements $TenderApprovalsByIdResponseCopyWith<$Res> { + _$TenderApprovalsByIdResponseCopyWithImpl(this._self, this._then); + + final TenderApprovalsByIdResponse _self; + final $Res Function(TenderApprovalsByIdResponse) _then; + +/// Create a copy of TenderApprovalsByIdResponse +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? message = freezed,Object? success = freezed,Object? error = freezed,Object? data = freezed,}) { + return _then(_self.copyWith( +message: freezed == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String?,success: freezed == success ? _self.success : success // ignore: cast_nullable_to_non_nullable +as bool?,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable +as ErrorModel?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable +as TenderApprovalsData?, + )); +} +/// Create a copy of TenderApprovalsByIdResponse +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$ErrorModelCopyWith<$Res>? get error { + if (_self.error == null) { + return null; + } + + return $ErrorModelCopyWith<$Res>(_self.error!, (value) { + return _then(_self.copyWith(error: value)); + }); +}/// Create a copy of TenderApprovalsByIdResponse +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$TenderApprovalsDataCopyWith<$Res>? get data { + if (_self.data == null) { + return null; + } + + return $TenderApprovalsDataCopyWith<$Res>(_self.data!, (value) { + return _then(_self.copyWith(data: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [TenderApprovalsByIdResponse]. +extension TenderApprovalsByIdResponsePatterns on TenderApprovalsByIdResponse { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _TenderApprovalsByIdResponse value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _TenderApprovalsByIdResponse() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _TenderApprovalsByIdResponse value) $default,){ +final _that = this; +switch (_that) { +case _TenderApprovalsByIdResponse(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _TenderApprovalsByIdResponse value)? $default,){ +final _that = this; +switch (_that) { +case _TenderApprovalsByIdResponse() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String? message, bool? success, ErrorModel? error, TenderApprovalsData? data)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _TenderApprovalsByIdResponse() when $default != null: +return $default(_that.message,_that.success,_that.error,_that.data);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String? message, bool? success, ErrorModel? error, TenderApprovalsData? data) $default,) {final _that = this; +switch (_that) { +case _TenderApprovalsByIdResponse(): +return $default(_that.message,_that.success,_that.error,_that.data);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? message, bool? success, ErrorModel? error, TenderApprovalsData? data)? $default,) {final _that = this; +switch (_that) { +case _TenderApprovalsByIdResponse() when $default != null: +return $default(_that.message,_that.success,_that.error,_that.data);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _TenderApprovalsByIdResponse implements TenderApprovalsByIdResponse { + const _TenderApprovalsByIdResponse({required this.message, required this.success, required this.error, required this.data}); + factory _TenderApprovalsByIdResponse.fromJson(Map json) => _$TenderApprovalsByIdResponseFromJson(json); + +@override final String? message; +@override final bool? success; +@override final ErrorModel? error; +@override final TenderApprovalsData? data; + +/// Create a copy of TenderApprovalsByIdResponse +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$TenderApprovalsByIdResponseCopyWith<_TenderApprovalsByIdResponse> get copyWith => __$TenderApprovalsByIdResponseCopyWithImpl<_TenderApprovalsByIdResponse>(this, _$identity); + +@override +Map toJson() { + return _$TenderApprovalsByIdResponseToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _TenderApprovalsByIdResponse&&(identical(other.message, message) || other.message == message)&&(identical(other.success, success) || other.success == success)&&(identical(other.error, error) || other.error == error)&&(identical(other.data, data) || other.data == data)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,message,success,error,data); + +@override +String toString() { + return 'TenderApprovalsByIdResponse(message: $message, success: $success, error: $error, data: $data)'; +} + + +} + +/// @nodoc +abstract mixin class _$TenderApprovalsByIdResponseCopyWith<$Res> implements $TenderApprovalsByIdResponseCopyWith<$Res> { + factory _$TenderApprovalsByIdResponseCopyWith(_TenderApprovalsByIdResponse value, $Res Function(_TenderApprovalsByIdResponse) _then) = __$TenderApprovalsByIdResponseCopyWithImpl; +@override @useResult +$Res call({ + String? message, bool? success, ErrorModel? error, TenderApprovalsData? data +}); + + +@override $ErrorModelCopyWith<$Res>? get error;@override $TenderApprovalsDataCopyWith<$Res>? get data; + +} +/// @nodoc +class __$TenderApprovalsByIdResponseCopyWithImpl<$Res> + implements _$TenderApprovalsByIdResponseCopyWith<$Res> { + __$TenderApprovalsByIdResponseCopyWithImpl(this._self, this._then); + + final _TenderApprovalsByIdResponse _self; + final $Res Function(_TenderApprovalsByIdResponse) _then; + +/// Create a copy of TenderApprovalsByIdResponse +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? message = freezed,Object? success = freezed,Object? error = freezed,Object? data = freezed,}) { + return _then(_TenderApprovalsByIdResponse( +message: freezed == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String?,success: freezed == success ? _self.success : success // ignore: cast_nullable_to_non_nullable +as bool?,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable +as ErrorModel?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable +as TenderApprovalsData?, + )); +} + +/// Create a copy of TenderApprovalsByIdResponse +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$ErrorModelCopyWith<$Res>? get error { + if (_self.error == null) { + return null; + } + + return $ErrorModelCopyWith<$Res>(_self.error!, (value) { + return _then(_self.copyWith(error: value)); + }); +}/// Create a copy of TenderApprovalsByIdResponse +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$TenderApprovalsDataCopyWith<$Res>? get data { + if (_self.data == null) { + return null; + } + + return $TenderApprovalsDataCopyWith<$Res>(_self.data!, (value) { + return _then(_self.copyWith(data: value)); + }); +} +} + +// dart format on diff --git a/lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.g.dart b/lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.g.dart new file mode 100644 index 0000000..aa48e94 --- /dev/null +++ b/lib/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.g.dart @@ -0,0 +1,31 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'tender_approvals_by_id_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_TenderApprovalsByIdResponse _$TenderApprovalsByIdResponseFromJson( + Map json, +) => _TenderApprovalsByIdResponse( + message: json['message'] as String?, + success: json['success'] as bool?, + error: + json['error'] == null + ? null + : ErrorModel.fromJson(json['error'] as Map), + data: + json['data'] == null + ? null + : TenderApprovalsData.fromJson(json['data'] as Map), +); + +Map _$TenderApprovalsByIdResponseToJson( + _TenderApprovalsByIdResponse instance, +) => { + 'message': instance.message, + 'success': instance.success, + 'error': instance.error, + 'data': instance.data, +}; diff --git a/lib/data/services/model/tender_approvals_data/tender_approvals_data.dart b/lib/data/services/model/tender_approvals_data/tender_approvals_data.dart index a5141ba..b69e111 100644 --- a/lib/data/services/model/tender_approvals_data/tender_approvals_data.dart +++ b/lib/data/services/model/tender_approvals_data/tender_approvals_data.dart @@ -1,3 +1,4 @@ +<<<<<<< HEAD // ignore_for_file: invalid_annotation_target import 'package:freezed_annotation/freezed_annotation.dart'; @@ -22,3 +23,29 @@ abstract class TenderApprovalsData with _$TenderApprovalsData { factory TenderApprovalsData.fromJson(Map json) => _$TenderApprovalsDataFromJson(json); } +======= +// ignore_for_file: invalid_annotation_target + +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../tender_data/tender_data.dart'; + +part 'tender_approvals_data.freezed.dart'; +part 'tender_approvals_data.g.dart'; + +@freezed +abstract class TenderApprovalsData with _$TenderApprovalsData { + const factory TenderApprovalsData({ + required String? id, + required String? status, + @JsonKey(name: 'tender_id') required String? tenderId, + @JsonKey(name: 'company_id') required String? companyId, + @JsonKey(name: 'submission_mode') required String? submissionMode, + @JsonKey(name: 'created_at') required int? createdAt, + required TenderData? tender, + }) = _TenderApprovalsData; + + factory TenderApprovalsData.fromJson(Map json) => + _$TenderApprovalsDataFromJson(json); +} +>>>>>>> tenders_approval diff --git a/lib/data/services/model/tender_approvals_response/tender_approvals_response.dart b/lib/data/services/model/tender_approvals_response/tender_approvals_response.dart index b5355b6..3e58fce 100644 --- a/lib/data/services/model/tender_approvals_response/tender_approvals_response.dart +++ b/lib/data/services/model/tender_approvals_response/tender_approvals_response.dart @@ -1,3 +1,4 @@ +<<<<<<< HEAD // ignore_for_file: invalid_annotation_target import 'package:freezed_annotation/freezed_annotation.dart'; @@ -20,3 +21,27 @@ abstract class TenderApprovalsResponse with _$TenderApprovalsResponse { factory TenderApprovalsResponse.fromJson(Map json) => _$TenderApprovalsResponseFromJson(json); } +======= +// ignore_for_file: invalid_annotation_target + +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../error/error_model.dart'; +import '../tender_approvals_data/tender_approvals_data.dart'; + +part 'tender_approvals_response.freezed.dart'; +part 'tender_approvals_response.g.dart'; + +@freezed +abstract class TenderApprovalsResponse with _$TenderApprovalsResponse { + const factory TenderApprovalsResponse({ + required String? message, + required bool? success, + required ErrorModel? error, + required List? data, + }) = _TenderApprovalsResponse; + + factory TenderApprovalsResponse.fromJson(Map json) => + _$TenderApprovalsResponseFromJson(json); +} +>>>>>>> tenders_approval diff --git a/lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.dart b/lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.dart new file mode 100644 index 0000000..ca0ce1a --- /dev/null +++ b/lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.dart @@ -0,0 +1,21 @@ +// ignore_for_file: invalid_annotation_target + +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'tender_approvals_toggle_data.freezed.dart'; +part 'tender_approvals_toggle_data.g.dart'; + +@freezed +abstract class TenderApprovalsToggleData with _$TenderApprovalsToggleData { + const factory TenderApprovalsToggleData({ + required String? id, + @JsonKey(name: 'tender_id') required String? tenderId, + @JsonKey(name: 'company_id') required String? companyId, + @JsonKey(name: 'submission_mode') required String? submissionMode, + @JsonKey(name: 'status') required String? status, + @JsonKey(name: 'created_at') required int? createdAt, + }) = _TenderApprovalsToggleData; + + factory TenderApprovalsToggleData.fromJson(Map json) => + _$TenderApprovalsToggleDataFromJson(json); +} diff --git a/lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.freezed.dart b/lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.freezed.dart new file mode 100644 index 0000000..c062cee --- /dev/null +++ b/lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.freezed.dart @@ -0,0 +1,292 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'tender_approvals_toggle_data.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$TenderApprovalsToggleData { + + String? get id;@JsonKey(name: 'tender_id') String? get tenderId;@JsonKey(name: 'company_id') String? get companyId;@JsonKey(name: 'submission_mode') String? get submissionMode;@JsonKey(name: 'status') String? get status;@JsonKey(name: 'created_at') int? get createdAt; +/// Create a copy of TenderApprovalsToggleData +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$TenderApprovalsToggleDataCopyWith get copyWith => _$TenderApprovalsToggleDataCopyWithImpl(this as TenderApprovalsToggleData, _$identity); + + /// Serializes this TenderApprovalsToggleData to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is TenderApprovalsToggleData&&(identical(other.id, id) || other.id == id)&&(identical(other.tenderId, tenderId) || other.tenderId == tenderId)&&(identical(other.companyId, companyId) || other.companyId == companyId)&&(identical(other.submissionMode, submissionMode) || other.submissionMode == submissionMode)&&(identical(other.status, status) || other.status == status)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,tenderId,companyId,submissionMode,status,createdAt); + +@override +String toString() { + return 'TenderApprovalsToggleData(id: $id, tenderId: $tenderId, companyId: $companyId, submissionMode: $submissionMode, status: $status, createdAt: $createdAt)'; +} + + +} + +/// @nodoc +abstract mixin class $TenderApprovalsToggleDataCopyWith<$Res> { + factory $TenderApprovalsToggleDataCopyWith(TenderApprovalsToggleData value, $Res Function(TenderApprovalsToggleData) _then) = _$TenderApprovalsToggleDataCopyWithImpl; +@useResult +$Res call({ + String? id,@JsonKey(name: 'tender_id') String? tenderId,@JsonKey(name: 'company_id') String? companyId,@JsonKey(name: 'submission_mode') String? submissionMode,@JsonKey(name: 'status') String? status,@JsonKey(name: 'created_at') int? createdAt +}); + + + + +} +/// @nodoc +class _$TenderApprovalsToggleDataCopyWithImpl<$Res> + implements $TenderApprovalsToggleDataCopyWith<$Res> { + _$TenderApprovalsToggleDataCopyWithImpl(this._self, this._then); + + final TenderApprovalsToggleData _self; + final $Res Function(TenderApprovalsToggleData) _then; + +/// Create a copy of TenderApprovalsToggleData +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = freezed,Object? tenderId = freezed,Object? companyId = freezed,Object? submissionMode = freezed,Object? status = freezed,Object? createdAt = freezed,}) { + return _then(_self.copyWith( +id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String?,tenderId: freezed == tenderId ? _self.tenderId : tenderId // ignore: cast_nullable_to_non_nullable +as String?,companyId: freezed == companyId ? _self.companyId : companyId // ignore: cast_nullable_to_non_nullable +as String?,submissionMode: freezed == submissionMode ? _self.submissionMode : submissionMode // ignore: cast_nullable_to_non_nullable +as String?,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable +as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as int?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [TenderApprovalsToggleData]. +extension TenderApprovalsToggleDataPatterns on TenderApprovalsToggleData { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _TenderApprovalsToggleData value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _TenderApprovalsToggleData() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _TenderApprovalsToggleData value) $default,){ +final _that = this; +switch (_that) { +case _TenderApprovalsToggleData(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _TenderApprovalsToggleData value)? $default,){ +final _that = this; +switch (_that) { +case _TenderApprovalsToggleData() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String? id, @JsonKey(name: 'tender_id') String? tenderId, @JsonKey(name: 'company_id') String? companyId, @JsonKey(name: 'submission_mode') String? submissionMode, @JsonKey(name: 'status') String? status, @JsonKey(name: 'created_at') int? createdAt)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _TenderApprovalsToggleData() when $default != null: +return $default(_that.id,_that.tenderId,_that.companyId,_that.submissionMode,_that.status,_that.createdAt);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String? id, @JsonKey(name: 'tender_id') String? tenderId, @JsonKey(name: 'company_id') String? companyId, @JsonKey(name: 'submission_mode') String? submissionMode, @JsonKey(name: 'status') String? status, @JsonKey(name: 'created_at') int? createdAt) $default,) {final _that = this; +switch (_that) { +case _TenderApprovalsToggleData(): +return $default(_that.id,_that.tenderId,_that.companyId,_that.submissionMode,_that.status,_that.createdAt);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? id, @JsonKey(name: 'tender_id') String? tenderId, @JsonKey(name: 'company_id') String? companyId, @JsonKey(name: 'submission_mode') String? submissionMode, @JsonKey(name: 'status') String? status, @JsonKey(name: 'created_at') int? createdAt)? $default,) {final _that = this; +switch (_that) { +case _TenderApprovalsToggleData() when $default != null: +return $default(_that.id,_that.tenderId,_that.companyId,_that.submissionMode,_that.status,_that.createdAt);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _TenderApprovalsToggleData implements TenderApprovalsToggleData { + const _TenderApprovalsToggleData({required this.id, @JsonKey(name: 'tender_id') required this.tenderId, @JsonKey(name: 'company_id') required this.companyId, @JsonKey(name: 'submission_mode') required this.submissionMode, @JsonKey(name: 'status') required this.status, @JsonKey(name: 'created_at') required this.createdAt}); + factory _TenderApprovalsToggleData.fromJson(Map json) => _$TenderApprovalsToggleDataFromJson(json); + +@override final String? id; +@override@JsonKey(name: 'tender_id') final String? tenderId; +@override@JsonKey(name: 'company_id') final String? companyId; +@override@JsonKey(name: 'submission_mode') final String? submissionMode; +@override@JsonKey(name: 'status') final String? status; +@override@JsonKey(name: 'created_at') final int? createdAt; + +/// Create a copy of TenderApprovalsToggleData +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$TenderApprovalsToggleDataCopyWith<_TenderApprovalsToggleData> get copyWith => __$TenderApprovalsToggleDataCopyWithImpl<_TenderApprovalsToggleData>(this, _$identity); + +@override +Map toJson() { + return _$TenderApprovalsToggleDataToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _TenderApprovalsToggleData&&(identical(other.id, id) || other.id == id)&&(identical(other.tenderId, tenderId) || other.tenderId == tenderId)&&(identical(other.companyId, companyId) || other.companyId == companyId)&&(identical(other.submissionMode, submissionMode) || other.submissionMode == submissionMode)&&(identical(other.status, status) || other.status == status)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,tenderId,companyId,submissionMode,status,createdAt); + +@override +String toString() { + return 'TenderApprovalsToggleData(id: $id, tenderId: $tenderId, companyId: $companyId, submissionMode: $submissionMode, status: $status, createdAt: $createdAt)'; +} + + +} + +/// @nodoc +abstract mixin class _$TenderApprovalsToggleDataCopyWith<$Res> implements $TenderApprovalsToggleDataCopyWith<$Res> { + factory _$TenderApprovalsToggleDataCopyWith(_TenderApprovalsToggleData value, $Res Function(_TenderApprovalsToggleData) _then) = __$TenderApprovalsToggleDataCopyWithImpl; +@override @useResult +$Res call({ + String? id,@JsonKey(name: 'tender_id') String? tenderId,@JsonKey(name: 'company_id') String? companyId,@JsonKey(name: 'submission_mode') String? submissionMode,@JsonKey(name: 'status') String? status,@JsonKey(name: 'created_at') int? createdAt +}); + + + + +} +/// @nodoc +class __$TenderApprovalsToggleDataCopyWithImpl<$Res> + implements _$TenderApprovalsToggleDataCopyWith<$Res> { + __$TenderApprovalsToggleDataCopyWithImpl(this._self, this._then); + + final _TenderApprovalsToggleData _self; + final $Res Function(_TenderApprovalsToggleData) _then; + +/// Create a copy of TenderApprovalsToggleData +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = freezed,Object? tenderId = freezed,Object? companyId = freezed,Object? submissionMode = freezed,Object? status = freezed,Object? createdAt = freezed,}) { + return _then(_TenderApprovalsToggleData( +id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String?,tenderId: freezed == tenderId ? _self.tenderId : tenderId // ignore: cast_nullable_to_non_nullable +as String?,companyId: freezed == companyId ? _self.companyId : companyId // ignore: cast_nullable_to_non_nullable +as String?,submissionMode: freezed == submissionMode ? _self.submissionMode : submissionMode // ignore: cast_nullable_to_non_nullable +as String?,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable +as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as int?, + )); +} + + +} + +// dart format on diff --git a/lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.g.dart b/lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.g.dart new file mode 100644 index 0000000..2c97758 --- /dev/null +++ b/lib/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.g.dart @@ -0,0 +1,29 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'tender_approvals_toggle_data.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_TenderApprovalsToggleData _$TenderApprovalsToggleDataFromJson( + Map json, +) => _TenderApprovalsToggleData( + id: json['id'] as String?, + tenderId: json['tender_id'] as String?, + companyId: json['company_id'] as String?, + submissionMode: json['submission_mode'] as String?, + status: json['status'] as String?, + createdAt: (json['created_at'] as num?)?.toInt(), +); + +Map _$TenderApprovalsToggleDataToJson( + _TenderApprovalsToggleData instance, +) => { + 'id': instance.id, + 'tender_id': instance.tenderId, + 'company_id': instance.companyId, + 'submission_mode': instance.submissionMode, + 'status': instance.status, + 'created_at': instance.createdAt, +}; diff --git a/lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart b/lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart new file mode 100644 index 0000000..4209e4e --- /dev/null +++ b/lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart @@ -0,0 +1,21 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:tm_app/data/services/model/error/error_model.dart'; + +import '../tender_approvals_toggle_data/tender_approvals_toggle_data.dart'; + +part 'tender_approvals_toggle_response.freezed.dart'; +part 'tender_approvals_toggle_response.g.dart'; + +@freezed +abstract class TenderApprovalsToggleResponse + with _$TenderApprovalsToggleResponse { + const factory TenderApprovalsToggleResponse({ + required String? message, + required bool? success, + required ErrorModel? error, + required TenderApprovalsToggleData? data, + }) = _TenderApprovalsToggleResponse; + + factory TenderApprovalsToggleResponse.fromJson(Map json) => + _$TenderApprovalsToggleResponseFromJson(json); +} diff --git a/lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.freezed.dart b/lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.freezed.dart new file mode 100644 index 0000000..f5aaad8 --- /dev/null +++ b/lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.freezed.dart @@ -0,0 +1,334 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'tender_approvals_toggle_response.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$TenderApprovalsToggleResponse { + + String? get message; bool? get success; ErrorModel? get error; TenderApprovalsToggleData? get data; +/// Create a copy of TenderApprovalsToggleResponse +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$TenderApprovalsToggleResponseCopyWith get copyWith => _$TenderApprovalsToggleResponseCopyWithImpl(this as TenderApprovalsToggleResponse, _$identity); + + /// Serializes this TenderApprovalsToggleResponse to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is TenderApprovalsToggleResponse&&(identical(other.message, message) || other.message == message)&&(identical(other.success, success) || other.success == success)&&(identical(other.error, error) || other.error == error)&&(identical(other.data, data) || other.data == data)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,message,success,error,data); + +@override +String toString() { + return 'TenderApprovalsToggleResponse(message: $message, success: $success, error: $error, data: $data)'; +} + + +} + +/// @nodoc +abstract mixin class $TenderApprovalsToggleResponseCopyWith<$Res> { + factory $TenderApprovalsToggleResponseCopyWith(TenderApprovalsToggleResponse value, $Res Function(TenderApprovalsToggleResponse) _then) = _$TenderApprovalsToggleResponseCopyWithImpl; +@useResult +$Res call({ + String? message, bool? success, ErrorModel? error, TenderApprovalsToggleData? data +}); + + +$ErrorModelCopyWith<$Res>? get error;$TenderApprovalsToggleDataCopyWith<$Res>? get data; + +} +/// @nodoc +class _$TenderApprovalsToggleResponseCopyWithImpl<$Res> + implements $TenderApprovalsToggleResponseCopyWith<$Res> { + _$TenderApprovalsToggleResponseCopyWithImpl(this._self, this._then); + + final TenderApprovalsToggleResponse _self; + final $Res Function(TenderApprovalsToggleResponse) _then; + +/// Create a copy of TenderApprovalsToggleResponse +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? message = freezed,Object? success = freezed,Object? error = freezed,Object? data = freezed,}) { + return _then(_self.copyWith( +message: freezed == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String?,success: freezed == success ? _self.success : success // ignore: cast_nullable_to_non_nullable +as bool?,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable +as ErrorModel?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable +as TenderApprovalsToggleData?, + )); +} +/// Create a copy of TenderApprovalsToggleResponse +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$ErrorModelCopyWith<$Res>? get error { + if (_self.error == null) { + return null; + } + + return $ErrorModelCopyWith<$Res>(_self.error!, (value) { + return _then(_self.copyWith(error: value)); + }); +}/// Create a copy of TenderApprovalsToggleResponse +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$TenderApprovalsToggleDataCopyWith<$Res>? get data { + if (_self.data == null) { + return null; + } + + return $TenderApprovalsToggleDataCopyWith<$Res>(_self.data!, (value) { + return _then(_self.copyWith(data: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [TenderApprovalsToggleResponse]. +extension TenderApprovalsToggleResponsePatterns on TenderApprovalsToggleResponse { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _TenderApprovalsToggleResponse value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _TenderApprovalsToggleResponse() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _TenderApprovalsToggleResponse value) $default,){ +final _that = this; +switch (_that) { +case _TenderApprovalsToggleResponse(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _TenderApprovalsToggleResponse value)? $default,){ +final _that = this; +switch (_that) { +case _TenderApprovalsToggleResponse() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String? message, bool? success, ErrorModel? error, TenderApprovalsToggleData? data)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _TenderApprovalsToggleResponse() when $default != null: +return $default(_that.message,_that.success,_that.error,_that.data);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String? message, bool? success, ErrorModel? error, TenderApprovalsToggleData? data) $default,) {final _that = this; +switch (_that) { +case _TenderApprovalsToggleResponse(): +return $default(_that.message,_that.success,_that.error,_that.data);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? message, bool? success, ErrorModel? error, TenderApprovalsToggleData? data)? $default,) {final _that = this; +switch (_that) { +case _TenderApprovalsToggleResponse() when $default != null: +return $default(_that.message,_that.success,_that.error,_that.data);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _TenderApprovalsToggleResponse implements TenderApprovalsToggleResponse { + const _TenderApprovalsToggleResponse({required this.message, required this.success, required this.error, required this.data}); + factory _TenderApprovalsToggleResponse.fromJson(Map json) => _$TenderApprovalsToggleResponseFromJson(json); + +@override final String? message; +@override final bool? success; +@override final ErrorModel? error; +@override final TenderApprovalsToggleData? data; + +/// Create a copy of TenderApprovalsToggleResponse +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$TenderApprovalsToggleResponseCopyWith<_TenderApprovalsToggleResponse> get copyWith => __$TenderApprovalsToggleResponseCopyWithImpl<_TenderApprovalsToggleResponse>(this, _$identity); + +@override +Map toJson() { + return _$TenderApprovalsToggleResponseToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _TenderApprovalsToggleResponse&&(identical(other.message, message) || other.message == message)&&(identical(other.success, success) || other.success == success)&&(identical(other.error, error) || other.error == error)&&(identical(other.data, data) || other.data == data)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,message,success,error,data); + +@override +String toString() { + return 'TenderApprovalsToggleResponse(message: $message, success: $success, error: $error, data: $data)'; +} + + +} + +/// @nodoc +abstract mixin class _$TenderApprovalsToggleResponseCopyWith<$Res> implements $TenderApprovalsToggleResponseCopyWith<$Res> { + factory _$TenderApprovalsToggleResponseCopyWith(_TenderApprovalsToggleResponse value, $Res Function(_TenderApprovalsToggleResponse) _then) = __$TenderApprovalsToggleResponseCopyWithImpl; +@override @useResult +$Res call({ + String? message, bool? success, ErrorModel? error, TenderApprovalsToggleData? data +}); + + +@override $ErrorModelCopyWith<$Res>? get error;@override $TenderApprovalsToggleDataCopyWith<$Res>? get data; + +} +/// @nodoc +class __$TenderApprovalsToggleResponseCopyWithImpl<$Res> + implements _$TenderApprovalsToggleResponseCopyWith<$Res> { + __$TenderApprovalsToggleResponseCopyWithImpl(this._self, this._then); + + final _TenderApprovalsToggleResponse _self; + final $Res Function(_TenderApprovalsToggleResponse) _then; + +/// Create a copy of TenderApprovalsToggleResponse +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? message = freezed,Object? success = freezed,Object? error = freezed,Object? data = freezed,}) { + return _then(_TenderApprovalsToggleResponse( +message: freezed == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String?,success: freezed == success ? _self.success : success // ignore: cast_nullable_to_non_nullable +as bool?,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable +as ErrorModel?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable +as TenderApprovalsToggleData?, + )); +} + +/// Create a copy of TenderApprovalsToggleResponse +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$ErrorModelCopyWith<$Res>? get error { + if (_self.error == null) { + return null; + } + + return $ErrorModelCopyWith<$Res>(_self.error!, (value) { + return _then(_self.copyWith(error: value)); + }); +}/// Create a copy of TenderApprovalsToggleResponse +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$TenderApprovalsToggleDataCopyWith<$Res>? get data { + if (_self.data == null) { + return null; + } + + return $TenderApprovalsToggleDataCopyWith<$Res>(_self.data!, (value) { + return _then(_self.copyWith(data: value)); + }); +} +} + +// dart format on diff --git a/lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.g.dart b/lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.g.dart new file mode 100644 index 0000000..d1de7eb --- /dev/null +++ b/lib/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.g.dart @@ -0,0 +1,33 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'tender_approvals_toggle_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_TenderApprovalsToggleResponse _$TenderApprovalsToggleResponseFromJson( + Map json, +) => _TenderApprovalsToggleResponse( + message: json['message'] as String?, + success: json['success'] as bool?, + error: + json['error'] == null + ? null + : ErrorModel.fromJson(json['error'] as Map), + data: + json['data'] == null + ? null + : TenderApprovalsToggleData.fromJson( + json['data'] as Map, + ), +); + +Map _$TenderApprovalsToggleResponseToJson( + _TenderApprovalsToggleResponse instance, +) => { + 'message': instance.message, + 'success': instance.success, + 'error': instance.error, + 'data': instance.data, +}; diff --git a/lib/data/services/tenders_service.dart b/lib/data/services/tenders_service.dart index e7110c6..709c398 100644 --- a/lib/data/services/tenders_service.dart +++ b/lib/data/services/tenders_service.dart @@ -2,6 +2,8 @@ import 'dart:convert'; import 'package:tm_app/core/utils/result.dart'; import 'package:tm_app/data/services/model/feedback_response/feedback_response.dart'; +import 'package:tm_app/data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart'; +import 'package:tm_app/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart'; import 'package:tm_app/data/services/model/tenders/tenders_response/tenders_response.dart'; import '../../core/network/network_manager.dart'; @@ -50,4 +52,34 @@ class TendersService { ); return result; } + + Future> toggleApprovals({ + required String tenderId, + required String submissionMode, + required String status, + }) async { + final data = jsonEncode({ + 'tender_id': tenderId, + 'submission_mode': submissionMode, + 'status': status, + }); + final result = await _networkManager.makeRequest( + '/api/v1/tender-approvals', + method: 'POST', + (json) => TenderApprovalsToggleResponse.fromJson(json), + data: data, + ); + return result; + } + + Future> getTenderApprovalsById({ + required String tenderId, + }) async { + final result = await _networkManager.makeRequest( + '/api/v1/tender-approvals/tender/$tenderId', + method: 'GET', + (json) => TenderApprovalsByIdResponse.fromJson(json), + ); + return result; + } } diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart index cef5472..230abd3 100644 --- a/lib/gen/assets.gen.dart +++ b/lib/gen/assets.gen.dart @@ -62,6 +62,9 @@ class $AssetsIconsGen { /// File path: assets/icons/menu.svg String get menu => 'assets/icons/menu.svg'; + /// File path: assets/icons/moon.svg + String get moon => 'assets/icons/moon.svg'; + /// File path: assets/icons/notification.svg String get notification => 'assets/icons/notification.svg'; @@ -74,6 +77,9 @@ class $AssetsIconsGen { /// File path: assets/icons/shield.svg String get shield => 'assets/icons/shield.svg'; + /// File path: assets/icons/sun.svg + String get sun => 'assets/icons/sun.svg'; + /// File path: assets/icons/task-square_active.svg String get taskSquareActive => 'assets/icons/task-square_active.svg'; @@ -114,10 +120,12 @@ class $AssetsIconsGen { like, location, menu, + moon, notification, profileCircle, profileCircleActive, shield, + sun, taskSquareActive, taskSquare, tenderLogoPng, diff --git a/lib/view_models/auth_view_model.dart b/lib/view_models/auth_view_model.dart index 047e5a7..c592f06 100644 --- a/lib/view_models/auth_view_model.dart +++ b/lib/view_models/auth_view_model.dart @@ -74,13 +74,6 @@ class AuthViewModel with ChangeNotifier { notifyListeners(); } - void forceLogout() { - _loggedInUser = null; - usernameController.clear(); - passwordController.clear(); - notifyListeners(); -} - Future logout() async { _errorMessage = null; notifyListeners(); diff --git a/lib/view_models/profile_view_model.dart b/lib/view_models/profile_view_model.dart index a434cdc..5776751 100644 --- a/lib/view_models/profile_view_model.dart +++ b/lib/view_models/profile_view_model.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:tm_app/data/repositories/auth_repository.dart'; import 'package:tm_app/data/services/model/profile_data/profile_data.dart'; -import 'package:tm_app/view_models/auth_view_model.dart'; import '../core/utils/result.dart'; import '../data/repositories/profile_repository.dart'; @@ -55,30 +53,25 @@ class ProfileViewModel with ChangeNotifier { Future localLogout() async { await _authRepository.localLogout(); _loggedOut = true; + notifyListeners(); } -Future logout(BuildContext context) async { - _errorMessage = null; - notifyListeners(); + Future logout(BuildContext context) async { + _errorMessage = null; + notifyListeners(); - final result = await _authRepository.logout(); + final result = await _authRepository.logout(); - switch (result) { - case Ok(): - await localLogout(); - // دسترسی به AuthViewModel و ریست یوزر - // چون با Provider کار می‌کنی: - final authViewModel = Provider.of(context, listen: false); - authViewModel.forceLogout(); - _loggedOut = true; - break; - case Error(): - _errorMessage = result.error.toString(); - break; + switch (result) { + case Ok(): + localLogout(); + break; + case Error(): + _errorMessage = result.error.toString(); + break; + } + + _errorMessage = null; + notifyListeners(); } - - _errorMessage = null; - notifyListeners(); -} - } diff --git a/lib/view_models/tender_detail_view_model.dart b/lib/view_models/tender_detail_view_model.dart index a591c62..61f5ed4 100644 --- a/lib/view_models/tender_detail_view_model.dart +++ b/lib/view_models/tender_detail_view_model.dart @@ -1,21 +1,33 @@ import 'package:flutter/material.dart'; import 'package:tm_app/core/utils/result.dart'; import 'package:tm_app/data/repositories/tender_detail_repository.dart'; +import 'package:tm_app/data/repositories/tenders_repository.dart'; import 'package:tm_app/data/services/model/tender_data/tender_data.dart'; import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart'; +import '../data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart'; + class TenderDetailViewModel with ChangeNotifier { final TenderDetailRepository _tenderDetailRepository; + final TendersRepository _tendersRepository; TenderDetailViewModel({ required TenderDetailRepository tenderDetailRepository, - }) : _tenderDetailRepository = tenderDetailRepository; + required TendersRepository tendersRepository, + }) : _tenderDetailRepository = tenderDetailRepository, + _tendersRepository = tendersRepository; bool _isLoading = false; + bool _isSubmitApprovalLoading = false; + bool _isRejectApprovalLoading = false; String? _errorMessage; TenderData? _tenderDetail; + bool approvalStatus = false; + bool get isLoading => _isLoading; + bool get isSubmitApprovalLoading => _isSubmitApprovalLoading; + bool get isRejectApprovalLoading => _isRejectApprovalLoading; String? get errorMessage => _errorMessage; TenderData? get tenderDetail => _tenderDetail; @@ -37,4 +49,56 @@ class TenderDetailViewModel with ChangeNotifier { _isLoading = false; notifyListeners(); } + + Future submitTenderApproval({ + required String tenderId, + required String submissionMode, + }) async { + _isSubmitApprovalLoading = true; + notifyListeners(); + final result = await _tendersRepository.toggleApprovals( + tenderId: tenderId, + status: 'approved', + submissionMode: submissionMode, + ); + switch (result) { + case Ok(): + approvalStatus = true; + break; + case Error(): + _errorMessage = result.error.toString(); + approvalStatus = false; + break; + } + _isSubmitApprovalLoading = false; + notifyListeners(); + _errorMessage = null; + notifyListeners(); + } + + Future rejectTenderApproval({ + required String tenderId, + required String submissionMode, + }) async { + _isRejectApprovalLoading = true; + notifyListeners(); + final result = await _tendersRepository.toggleApprovals( + tenderId: tenderId, + status: 'rejected', + submissionMode: submissionMode, + ); + switch (result) { + case Ok(): + approvalStatus = true; + break; + case Error(): + _errorMessage = result.error.toString(); + approvalStatus = false; + break; + } + _isRejectApprovalLoading = false; + notifyListeners(); + _errorMessage = null; + notifyListeners(); + } } diff --git a/lib/view_models/tenders_view_model.dart b/lib/view_models/tenders_view_model.dart index e245562..4d50b24 100644 --- a/lib/view_models/tenders_view_model.dart +++ b/lib/view_models/tenders_view_model.dart @@ -4,9 +4,13 @@ import 'package:flutter/material.dart'; import 'package:tm_app/data/repositories/tenders_repository.dart'; import 'package:tm_app/data/services/model/feedback_data/feedback_data.dart'; import 'package:tm_app/data/services/model/feedback_response/feedback_response.dart'; +import 'package:tm_app/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.dart'; +import 'package:tm_app/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart'; import 'package:tm_app/data/services/model/tenders/tenders_response/tenders_response.dart'; import '../core/utils/result.dart'; +import '../data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart'; +import '../data/services/model/tender_approvals_data/tender_approvals_data.dart'; class TendersViewModel with ChangeNotifier { final TendersRepository _tendersRepository; @@ -23,14 +27,20 @@ class TendersViewModel with ChangeNotifier { String? _errorMessage; TendersResponse? _tendersResponse; FeedbackData? _feedbackData; + TenderApprovalsData? _tenderApprovalData; + TenderApprovalsToggleData? _tenderApprovalToggleData; bool get isLoading => _isLoading; bool get isLoadingMore => _isLoadingMore; String? get errorMessage => _errorMessage; TendersResponse? get tendersResponse => _tendersResponse; FeedbackData? get feedbackData => _feedbackData; + TenderApprovalsData? get tenderApprovalData => _tenderApprovalData; + TenderApprovalsToggleData? get tenderApprovalToggleData => + _tenderApprovalToggleData; List feedbacks = []; + List tenderApprovals = []; int currentPage = 1; int _currentOffset = 0; @@ -53,6 +63,26 @@ class TendersViewModel with ChangeNotifier { return feedbacks.any((f) => f.tender == tenderId); } + /// Get tender approval for a specific tender + TenderApprovalsData? getTenderApprovalForTender(String tenderId) { + try { + return tenderApprovals.firstWhere((a) => a.tenderId == tenderId); + } catch (e) { + return null; + } + } + + /// Check if tender approval exists for a specific tender + bool hasTenderApprovalForTender(String tenderId) { + return tenderApprovals.any((a) => a.tenderId == tenderId); + } + + /// Get approval status for a specific tender + String? getApprovalStatusForTender(String tenderId) { + final approval = getTenderApprovalForTender(tenderId); + return approval?.status; + } + Future getTenders() async { _isLoading = true; _errorMessage = null; @@ -72,7 +102,9 @@ class TendersViewModel with ChangeNotifier { _hasMoreData = _tendersResponse!.data!.tenders!.length >= _pageSize; } if (_tendersResponse?.data?.tenders?.isNotEmpty == true) { + // Fetch feedback and approvals for the first tender only getTenderFeedback(_tendersResponse!.data!.tenders!.first.id!); + getTenderApprovals(_tendersResponse!.data!.tenders!.first.id!); } break; case Error(): @@ -169,6 +201,44 @@ class TendersViewModel with ChangeNotifier { notifyListeners(); } + Future getTenderApprovals(String tenderId) async { + _errorMessage = null; + notifyListeners(); + + final result = await _tendersRepository.getTenderApprovals( + tenderId: tenderId, + ); + switch (result) { + case Ok(): + _tenderApprovalData = result.value.data; + // Add or update _tenderApprovalData in tenderApprovals list by tender id + if (_tenderApprovalData != null) { + final index = tenderApprovals.indexWhere( + (a) => a.tenderId == _tenderApprovalData!.tenderId, + ); + if (index != -1) { + tenderApprovals[index] = _tenderApprovalData!; + log( + 'Updated approval for tender: ${_tenderApprovalData!.tenderId}', + ); + } else { + tenderApprovals.add(_tenderApprovalData!); + log( + 'Added new approval for tender: ${_tenderApprovalData!.tenderId}', + ); + } + log('Total approvals: ${tenderApprovals.length}'); + } + break; + case Error(): + _errorMessage = result.error.toString(); + break; + } + notifyListeners(); + _errorMessage = null; + notifyListeners(); + } + Future feedback({ required String tenderId, required String feedbackType, @@ -202,4 +272,50 @@ class TendersViewModel with ChangeNotifier { _errorMessage = null; notifyListeners(); } + + Future toggleApprovals({ + required String tenderId, + required String submissionMode, + required String status, + }) async { + _errorMessage = null; + notifyListeners(); + final result = await _tendersRepository.toggleApprovals( + tenderId: tenderId, + submissionMode: submissionMode, + status: status, + ); + switch (result) { + case Ok(): + _tenderApprovalToggleData = result.value.data; + if (_tenderApprovalToggleData != null) { + // Convert TenderApprovalsToggleData to TenderApprovalsData + final approvalData = TenderApprovalsData( + id: _tenderApprovalToggleData!.id, + status: _tenderApprovalToggleData!.status, + tenderId: _tenderApprovalToggleData!.tenderId, + companyId: _tenderApprovalToggleData!.companyId, + submissionMode: _tenderApprovalToggleData!.submissionMode, + createdAt: _tenderApprovalToggleData!.createdAt, + tender: null, // Tender data is not included in toggle response + ); + + final index = tenderApprovals.indexWhere( + (a) => a.tenderId == approvalData.tenderId, + ); + if (index != -1) { + tenderApprovals[index] = approvalData; + } else { + tenderApprovals.add(approvalData); + } + } + break; + case Error(): + _errorMessage = result.error.toString(); + break; + } + notifyListeners(); + _errorMessage = null; + notifyListeners(); + } } diff --git a/lib/views/detail/pages/detail_desktop_page.dart b/lib/views/detail/pages/detail_desktop_page.dart index 453f858..7a2c7c0 100644 --- a/lib/views/detail/pages/detail_desktop_page.dart +++ b/lib/views/detail/pages/detail_desktop_page.dart @@ -49,7 +49,7 @@ class TenderDetailDesktopPage extends StatelessWidget { SizedBox(height: 32.0.h()), TenderDetailCard(detail: detail), SizedBox(height: 24.0.h()), - TenderDetailActions(isScreenBig: true), + TenderDetailActions(isScreenBig: true, detail: detail), ], ), ), diff --git a/lib/views/detail/pages/detail_mobile_page.dart b/lib/views/detail/pages/detail_mobile_page.dart index 30c9960..e786e39 100644 --- a/lib/views/detail/pages/detail_mobile_page.dart +++ b/lib/views/detail/pages/detail_mobile_page.dart @@ -45,7 +45,7 @@ class TenderDetailMobilePage extends StatelessWidget { SizedBox(height: 24.0.h()), TenderDetailCard(detail: detail), SizedBox(height: 24.0.h()), - TenderDetailActions(isScreenBig: false), + TenderDetailActions(isScreenBig: false, detail: detail), ], ), ), diff --git a/lib/views/detail/pages/detail_tablet_page.dart b/lib/views/detail/pages/detail_tablet_page.dart index 91cced4..0a5f08f 100644 --- a/lib/views/detail/pages/detail_tablet_page.dart +++ b/lib/views/detail/pages/detail_tablet_page.dart @@ -49,7 +49,7 @@ class TenderDetailTabletPage extends StatelessWidget { SizedBox(height: 28.0.h()), TenderDetailCard(detail: detail), SizedBox(height: 24.0.h()), - TenderDetailActions(isScreenBig: true), + TenderDetailActions(isScreenBig: true, detail: detail), ], ), ), diff --git a/lib/views/detail/widgets/tender_detail_action.dart b/lib/views/detail/widgets/tender_detail_action.dart index 7cc9bc8..7e7f6af 100644 --- a/lib/views/detail/widgets/tender_detail_action.dart +++ b/lib/views/detail/widgets/tender_detail_action.dart @@ -1,12 +1,22 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.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/view_models/tender_detail_view_model.dart'; import 'package:tm_app/views/shared/base_button.dart'; +import 'package:tm_app/views/shared/select_submission_bottom_sheet.dart'; + +import '../../../data/services/model/tender_data/tender_data.dart'; class TenderDetailActions extends StatelessWidget { final bool isScreenBig; - const TenderDetailActions({required this.isScreenBig, super.key}); + final TenderData detail; + const TenderDetailActions({ + required this.isScreenBig, + required this.detail, + super.key, + }); @override Widget build(BuildContext context) { @@ -36,22 +46,69 @@ class TenderDetailActions extends StatelessWidget { ) : Column( children: [ - BaseButton( - isEnabled: true, - text: AppStrings.tenderSubmitButton, - backgroundColor: AppColors.primary30, - textColor: AppColors.mainBlue, - onPressed: () {}, + Consumer( + builder: (context, viewModel, child) { + return viewModel.isSubmitApprovalLoading + ? BaseButton( + isEnabled: true, + text: AppStrings.tenderSubmitButton, + backgroundColor: AppColors.primary30, + textColor: AppColors.mainBlue, + isLoading: true, + onPressed: () {}, + ) + : BaseButton( + isEnabled: true, + text: AppStrings.tenderSubmitButton, + backgroundColor: AppColors.primary30, + textColor: AppColors.mainBlue, + onPressed: () { + showModalBottomSheet( + isDismissible: true, + context: context, + builder: (context) { + return SelectSubmissionBottomSheet( + onConfirm: (value) { + viewModel.submitTenderApproval( + tenderId: detail.id!, + submissionMode: value, + ); + }, + ); + }, + ); + }, + ); + }, ), SizedBox(height: 16.0.h()), - BaseButton( - isEnabled: true, - text: AppStrings.tenderRejectButton, - borderColor: AppColors.red10, - textColor: AppColors.red10, - backgroundColor: AppColors.backgroundColor, - borderWidth: 1, - onPressed: () {}, + Consumer( + builder: (context, viewModel, child) { + return viewModel.isRejectApprovalLoading + ? BaseButton( + isEnabled: true, + text: AppStrings.tenderRejectButton, + borderColor: AppColors.error, + textColor: AppColors.error, + backgroundColor: AppColors.backgroundColor, + borderWidth: 1, + onPressed: () {}, + ) + : BaseButton( + isEnabled: true, + text: AppStrings.tenderRejectButton, + borderColor: AppColors.error, + textColor: AppColors.error, + backgroundColor: AppColors.backgroundColor, + borderWidth: 1, + onPressed: () { + viewModel.rejectTenderApproval( + tenderId: detail.id!, + submissionMode: 'self-apply', + ); + }, + ); + }, ), SizedBox(height: 16.0.h()), ], diff --git a/lib/views/home/tenders_list_item.dart b/lib/views/home/tenders_list_item.dart index 0756a0f..e9f3d42 100644 --- a/lib/views/home/tenders_list_item.dart +++ b/lib/views/home/tenders_list_item.dart @@ -46,7 +46,7 @@ class TendersListItem extends StatelessWidget { vertical: 5.0.h(), ), decoration: BoxDecoration( - color: AppColors.primary2, + color: AppColors.primary20, borderRadius: BorderRadius.circular(4), ), child: Row( diff --git a/lib/views/profile/pages/m_profile_page.dart b/lib/views/profile/pages/m_profile_page.dart index bc065ae..7f5364f 100644 --- a/lib/views/profile/pages/m_profile_page.dart +++ b/lib/views/profile/pages/m_profile_page.dart @@ -1,13 +1,15 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/view_models/profile_view_model.dart'; +import 'package:tm_app/views/profile/widgets/theme_toggle.dart'; import 'package:tm_app/views/shared/tender_app_bar.dart'; +import '../../../core/constants/assets.dart'; import '../../../core/constants/strings.dart'; import '../../../core/theme/colors.dart'; import '../../../core/utils/size_config.dart'; -import '../widgets/theme_toggle.dart'; import '../widgets/title_description.dart'; class MobileProfilePage extends StatefulWidget { @@ -88,36 +90,67 @@ class _MobileProfilePageState extends State { description: 'Telecommunications', ), TitleDescription(title: 'Founded', description: '2010'), - SizedBox(height: 24.0.h()), - // Theme Toggle - Container( - padding: EdgeInsets.symmetric( - horizontal: 16.0.w(), - vertical: 12.0.h(), + SizedBox(height: 32.0.h()), + + Align( + alignment: AlignmentDirectional.centerStart, + child: Text( + AppStrings.settings, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey70, + ), + ), + ), + SizedBox(height: 36.0.h()), + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0.w()), + child: Row( + children: [ + Text( + AppStrings.appTheme, + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey70, + ), + ), + Spacer(), + SvgPicture.asset(AssetsManager.sun), + SizedBox(width: 12.0.w()), + SizedBox( + width: 52.0.w(), + height: 32.0.h(), + child: ThemeToggle(), + ), + SizedBox(width: 12.0.w()), + SvgPicture.asset(AssetsManager.moon), + ], ), - decoration: BoxDecoration( - color: AppColors.surfaceColor, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.borderColor), - ), - child: const ThemeToggle(), ), - // ElevatedButton( - // onPressed: () => viewModel.logout(), - // child: const Text('Logout'), - // ), SizedBox(height: 24.0.h()), + Divider(color: AppColors.dividerColor, thickness: 1), + SizedBox(height: 24.0.h()), + Spacer(), InkWell( onTap: () => viewModel.logout(context), child: Container( width: double.infinity, - height: 45.0.h(), + height: 56.0.h(), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.borderColor), + color: AppColors.primary20, + borderRadius: BorderRadius.circular(100), ), alignment: Alignment.center, - child: Text('Logout'), + child: Text( + 'Logout', + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.primaryColor, + ), + ), ), ), ], diff --git a/lib/views/profile/widgets/theme_toggle.dart b/lib/views/profile/widgets/theme_toggle.dart index 522b84a..66f35f5 100644 --- a/lib/views/profile/widgets/theme_toggle.dart +++ b/lib/views/profile/widgets/theme_toggle.dart @@ -11,26 +11,12 @@ class ThemeToggle extends StatelessWidget { Widget build(BuildContext context) { final themeProvider = context.watch(); - return Row( - children: [ - Icon( - themeProvider.isDarkMode ? Icons.dark_mode : Icons.light_mode, - color: AppColors.primaryTextColor, - ), - const SizedBox(width: 8), - Text( - themeProvider.isDarkMode ? 'Dark Mode' : 'Light Mode', - style: TextStyle(color: AppColors.primaryTextColor, fontSize: 16), - ), - const Spacer(), - Switch( - value: themeProvider.isDarkMode, - onChanged: (value) { - themeProvider.toggleTheme(); - }, - activeColor: AppColors.primaryColor, - ), - ], + return Switch( + value: themeProvider.isDarkMode, + onChanged: (value) { + themeProvider.toggleTheme(); + }, + activeColor: AppColors.primaryColor, ); } } diff --git a/lib/views/shared/select_submission_bottom_sheet.dart b/lib/views/shared/select_submission_bottom_sheet.dart new file mode 100644 index 0000000..1ccb317 --- /dev/null +++ b/lib/views/shared/select_submission_bottom_sheet.dart @@ -0,0 +1,145 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +import '../../core/theme/colors.dart'; + +class SelectSubmissionBottomSheet extends StatefulWidget { + const SelectSubmissionBottomSheet({required this.onConfirm, super.key}); + final ValueChanged onConfirm; + + @override + State createState() => + _SelectSubmissionBottomSheetState(); +} + +class _SelectSubmissionBottomSheetState + extends State { + int selectedType = 0; + String type = 'self-apply'; + + @override + Widget build(BuildContext context) { + return Wrap( + children: [ + Container( + width: double.infinity, + // height: 272.0.h(), + padding: EdgeInsets.fromLTRB(24.0.w(), 24.0.h(), 24.0.w(), 33.0.h()), + decoration: BoxDecoration( + color: AppColors.backgroundColor, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + ), + ), + child: Column( + children: [ + Text( + 'Select Submission', + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey70, + ), + ), + SizedBox(height: 8.0.h()), + _submissionType( + title: 'self-apply', + isSelected: type == 'self-apply', + onTap: () { + selectedType = 0; + type = 'self-apply'; + setState(() {}); + }, + ), + SizedBox(height: 8.0.h()), + _submissionType( + title: 'Partnership', + isSelected: type == 'partnership', + onTap: () { + selectedType = 1; + type = 'partnership'; + setState(() {}); + }, + ), + SizedBox(height: 8.0.h()), + InkWell( + onTap: () { + widget.onConfirm(type); + context.pop(); + }, + child: Container( + width: double.infinity, + height: 56.0.h(), + decoration: BoxDecoration( + color: AppColors.primary20, + borderRadius: BorderRadius.circular(100), + ), + alignment: Alignment.center, + child: Text( + 'Confirm', + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.mainBlue, + ), + ), + ), + ), + ], + ), + ), + ], + ); + } + + Widget _submissionType({ + required VoidCallback onTap, + required String title, + required bool isSelected, + }) { + return InkWell( + onTap: onTap, + child: SizedBox( + width: double.infinity, + height: 56.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: 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, + ), + ), + ), + Text( + title, + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey80, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/views/tenders/widgets/main_tenders_slider.dart b/lib/views/tenders/widgets/main_tenders_slider.dart index cb48180..a13b439 100644 --- a/lib/views/tenders/widgets/main_tenders_slider.dart +++ b/lib/views/tenders/widgets/main_tenders_slider.dart @@ -40,12 +40,15 @@ class _MainTendersSliderState extends State { currentPage = currentPage - 1; }); - // Fetch feedback for the previous tender if not already loaded + // Fetch feedback and approvals for the previous tender if not already loaded final viewModel = context.read(); final previousTenderId = widget.tenders[currentPage - 2].id!; if (!viewModel.hasFeedbackForTender(previousTenderId)) { viewModel.getTenderFeedback(previousTenderId); } + if (!viewModel.hasTenderApprovalForTender(previousTenderId)) { + viewModel.getTenderApprovals(previousTenderId); + } } void _goToNextPage() { @@ -61,12 +64,15 @@ class _MainTendersSliderState extends State { currentPage = currentPage + 1; }); - // Fetch feedback for the next tender if not already loaded + // Fetch feedback and approvals for the next tender if not already loaded final viewModel = context.read(); final nextTenderId = widget.tenders[currentPage].id!; if (!viewModel.hasFeedbackForTender(nextTenderId)) { viewModel.getTenderFeedback(nextTenderId); } + if (!viewModel.hasTenderApprovalForTender(nextTenderId)) { + viewModel.getTenderApprovals(nextTenderId); + } } @override @@ -95,11 +101,16 @@ class _MainTendersSliderState extends State { currentPage = index + 1; }); - // Fetch feedback for the new tender if not already loaded + // Fetch feedback and approvals for the new tender if not already loaded final viewModel = context.read(); if (!viewModel.hasFeedbackForTender(widget.tenders[index].id!)) { viewModel.getTenderFeedback(widget.tenders[index].id!); } + if (!viewModel.hasTenderApprovalForTender( + widget.tenders[index].id!, + )) { + viewModel.getTenderApprovals(widget.tenders[index].id!); + } // Check if we need to load more tenders (when user reaches near the end) if (index >= widget.tenders.length - 1 && @@ -154,28 +165,26 @@ class _MainTendersSliderState extends State { return Column( mainAxisSize: MainAxisSize.min, children: [ - viewModel.isLoadingMore ? - Padding( - padding: EdgeInsets.only(top: 4.0.h()), - child: SizedBox( - width: 16.0.w(), - height: 16.0.w(), - child: CircularProgressIndicator( - strokeWidth: 2.0, - color: AppColors.jellyBean, + viewModel.isLoadingMore + ? Padding( + padding: EdgeInsets.only(top: 4.0.h()), + child: SizedBox( + width: 16.0.w(), + height: 16.0.w(), + child: CircularProgressIndicator( + strokeWidth: 2.0, + color: AppColors.jellyBean, + ), + ), + ) + : Text( + '$currentPage/${widget.tenders.length}', + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.grey, ), ), - ): - Text( - '$currentPage/${widget.tenders.length}', - style: TextStyle( - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - color: AppColors.grey, - ), - ), - - ], ); } diff --git a/lib/views/tenders/widgets/tender_action_buttons_row.dart b/lib/views/tenders/widgets/tender_action_buttons_row.dart index 77b2b0a..8abadb6 100644 --- a/lib/views/tenders/widgets/tender_action_buttons_row.dart +++ b/lib/views/tenders/widgets/tender_action_buttons_row.dart @@ -8,6 +8,7 @@ import 'package:tm_app/view_models/tenders_view_model.dart'; import '../../../core/constants/assets.dart'; import '../../../core/theme/colors.dart'; import '../../../core/utils/size_config.dart'; +import '../../shared/select_submission_bottom_sheet.dart'; class TenderActionButtonsRow extends StatelessWidget { final TenderData tender; @@ -35,7 +36,7 @@ class TenderActionButtonsRow extends StatelessWidget { _rejectButton(viewModel), SizedBox(width: 32.0.w()), //submit button - _submitButton(viewModel), + _submitButton(viewModel, context), SizedBox(width: 32.0.w()), // Like button _likeButton(viewModel), @@ -46,12 +47,22 @@ class TenderActionButtonsRow extends StatelessWidget { } Widget _rejectButton(TendersViewModel viewModel) { + // Find approval for this specific tender + if (tender.id == null) return const SizedBox.shrink(); + + final approval = viewModel.getTenderApprovalForTender(tender.id!); + final isRejected = approval?.status == 'rejected'; + return Tooltip( message: AppStrings.reject, child: InkWell( splashColor: Colors.transparent, onTap: () { - // viewModel.toggleReject(tender); + viewModel.toggleApprovals( + tenderId: tender.id!, + submissionMode: 'self-apply', + status: 'rejected', + ); }, child: Column( children: [ @@ -61,22 +72,14 @@ class TenderActionButtonsRow extends StatelessWidget { decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( - color: - // tender.rejected ?? false - // ? AppColors.errorColor - // : - AppColors.grey60, + color: isRejected ? AppColors.errorColor : AppColors.grey60, width: 1.5.w(), ), ), alignment: Alignment.center, child: Icon( Icons.close, - color: - // tender.rejected ?? false - // ? AppColors.errorColor - // : - AppColors.grey60, + color: isRejected ? AppColors.errorColor : AppColors.grey60, size: 16, ), ), @@ -87,11 +90,7 @@ class TenderActionButtonsRow extends StatelessWidget { style: TextStyle( fontSize: 12.0.sp(), fontWeight: FontWeight.w400, - color: - // tender.rejected ?? false - // ? AppColors.errorColor - // : - AppColors.grey60, + color: isRejected ? AppColors.errorColor : AppColors.grey60, ), ), ], @@ -100,13 +99,41 @@ class TenderActionButtonsRow extends StatelessWidget { ); } - Widget _submitButton(TendersViewModel viewModel) { + Widget _submitButton(TendersViewModel viewModel, BuildContext context) { + // Find approval for this specific tender + if (tender.id == null) return const SizedBox.shrink(); + + final approval = viewModel.getTenderApprovalForTender(tender.id!); + final isApproved = approval?.status == 'approved'; + return Tooltip( message: AppStrings.submit, child: InkWell( splashColor: Colors.transparent, onTap: () { - // viewModel.toggleSubmit(tender); + if (isApproved) { + viewModel.toggleApprovals( + tenderId: tender.id!, + submissionMode: approval?.submissionMode ?? 'self-apply', + status: 'approved', + ); + } else { + showModalBottomSheet( + isDismissible: true, + context: context, + builder: (context) { + return SelectSubmissionBottomSheet( + onConfirm: (value) { + viewModel.toggleApprovals( + tenderId: tender.id!, + submissionMode: value, + status: 'approved', + ); + }, + ); + }, + ); + } }, child: Column( children: [ @@ -116,24 +143,15 @@ class TenderActionButtonsRow extends StatelessWidget { decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( - color: - // tender.submitted ?? false - // ? AppColors.successColor - // : - AppColors.grey60, + color: isApproved ? AppColors.successColor : AppColors.grey60, width: 1.5.w(), ), ), alignment: Alignment.center, - child: SvgPicture.asset( - AssetsManager.tick, - colorFilter: ColorFilter.mode( - // tender.submitted ?? false - // ? AppColors.successColor - // : - AppColors.grey60, - BlendMode.srcATop, - ), + child: Icon( + Icons.check, + color: isApproved ? AppColors.successColor : AppColors.grey60, + size: 16, ), ), SizedBox(height: 8.0.h()), @@ -143,11 +161,7 @@ class TenderActionButtonsRow extends StatelessWidget { style: TextStyle( fontSize: 12.0.sp(), fontWeight: FontWeight.w400, - color: - // tender.submitted ?? false - // ? AppColors.successColor - // : - AppColors.grey60, + color: isApproved ? AppColors.successColor : AppColors.grey60, ), ), ], @@ -158,6 +172,8 @@ class TenderActionButtonsRow extends StatelessWidget { Widget _dislikeButton(TendersViewModel viewModel) { // Find feedback for this specific tender + if (tender.id == null) return const SizedBox.shrink(); + final feedback = viewModel.getFeedbackForTender(tender.id!); final isDisliked = feedback?.feedbackType == 'dislike'; @@ -198,6 +214,8 @@ class TenderActionButtonsRow extends StatelessWidget { Widget _likeButton(TendersViewModel viewModel) { // Find feedback for this specific tender + if (tender.id == null) return const SizedBox.shrink(); + final feedback = viewModel.getFeedbackForTender(tender.id!); final isLiked = feedback?.feedbackType == 'like'; diff --git a/lib/views/tenders/widgets/tender_card.dart b/lib/views/tenders/widgets/tender_card.dart index a82afb3..78f8ace 100644 --- a/lib/views/tenders/widgets/tender_card.dart +++ b/lib/views/tenders/widgets/tender_card.dart @@ -55,6 +55,10 @@ class TenderCard extends StatelessWidget { _deadlineBadge(), SizedBox(height: 12.0.h()), + // Approval status badge + // _approvalStatusBadge(), + SizedBox(height: 12.0.h()), + // Title _tenderTitle(), SizedBox(height: 8.0.h()), @@ -148,6 +152,59 @@ class TenderCard extends StatelessWidget { ); } + // Widget _approvalStatusBadge() { + // return Consumer( + // builder: (context, viewModel, child) { + // final approvalStatus = viewModel.getApprovalStatusForTender(tender.id!); + // final statusText = approvalStatus ?? 'Pending'; + + // Color statusColor; + // switch (approvalStatus) { + // case 'approved': + // statusColor = AppColors.successColor; + // break; + // case 'rejected': + // statusColor = AppColors.errorColor; + // break; + // default: + // statusColor = AppColors.grey60; + // } + + // return Container( + // width: double.infinity, + // height: 24.0.h(), + // padding: EdgeInsets.symmetric(horizontal: 8.0.w()), + // decoration: BoxDecoration( + // color: AppColors.grey20, + // borderRadius: BorderRadius.circular(4), + // border: Border.all(color: statusColor), + // ), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Text( + // 'Approval Status', + // style: TextStyle( + // color: AppColors.grey80, + // fontSize: 14.0.sp(), + // fontWeight: FontWeight.w500, + // ), + // ), + // Text( + // statusText.toUpperCase(), + // style: TextStyle( + // color: statusColor, + // fontSize: 14.0.sp(), + // fontWeight: FontWeight.w500, + // ), + // ), + // ], + // ), + // ); + // }, + // ); + // } + Widget _tenderTitle() { return Text( tender.title ?? '', @@ -244,14 +301,15 @@ class TenderCard extends StatelessWidget { ), SizedBox(width: 8.0.w()), // Country flag placeholder - SizedBox( - width: 32.0.w(), - height: 21.0.h(), - child: CountryFlag.fromCountryCode( - tender.countryCode!, - shape: RoundedRectangle(4), + if (tender.countryCode != null) + SizedBox( + width: 32.0.w(), + height: 21.0.h(), + child: CountryFlag.fromCountryCode( + tender.countryCode!, + shape: RoundedRectangle(4), + ), ), - ), ], ), ); @@ -260,7 +318,9 @@ class TenderCard extends StatelessWidget { Widget _seeMoreButton(BuildContext context) { return InkWell( onTap: () { - TenderDetailRouteData(tenderId: tender.id!).push(context); + if (tender.id != null) { + TenderDetailRouteData(tenderId: tender.id!).push(context); + } }, child: Container( width: 108.0.w(),