Merge pull request 'tenders' (#48) from tenders into main
Reviewed-on: https://repo.ravanertebat.com/TM/tm_app/pulls/48
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/data/services/model/tenders/tender_dislike_response/tender_dislike_response.dart';
|
||||
import 'package:tm_app/data/services/model/tenders/tender_like_response/tender_like_response.dart';
|
||||
import 'package:tm_app/data/services/model/tenders/tender_reject_response/tender_reject_response.dart';
|
||||
import 'package:tm_app/data/services/model/tenders/tender_submit_response/tender_submit_response.dart';
|
||||
import 'package:tm_app/data/services/model/feedback_response/feedback_response.dart';
|
||||
import 'package:tm_app/data/services/model/tenders/tenders_response/tenders_response.dart';
|
||||
import 'package:tm_app/data/services/tenders_service.dart';
|
||||
|
||||
@@ -11,23 +8,26 @@ class TendersRepository {
|
||||
: _tendersService = tendersService;
|
||||
final TendersService _tendersService;
|
||||
|
||||
Future<Result<TendersResponse>> getTenders() async {
|
||||
return _tendersService.getTenders();
|
||||
Future<Result<TendersResponse>> getTenders({
|
||||
required int limit,
|
||||
required int offset,
|
||||
}) async {
|
||||
return _tendersService.getTenders(limit: limit, offset: offset);
|
||||
}
|
||||
|
||||
Future<Result<TenderLikeResponse>> likeTender() async {
|
||||
return _tendersService.likeTender();
|
||||
Future<Result<FeedbackResponse>> getTenderFeedback({
|
||||
required String tenderId,
|
||||
}) async {
|
||||
return _tendersService.getTenderFeedback(tenderId: tenderId);
|
||||
}
|
||||
|
||||
Future<Result<TenderDislikeResponse>> dislikeTender() async {
|
||||
return _tendersService.dislikeTender();
|
||||
}
|
||||
|
||||
Future<Result<TenderSubmitResponse>> submitTender() async {
|
||||
return _tendersService.submitTender();
|
||||
}
|
||||
|
||||
Future<Result<TenderRejectResponse>> rejectTender() async {
|
||||
return _tendersService.rejectTender();
|
||||
Future<Result<FeedbackResponse>> feedback({
|
||||
required String tenderId,
|
||||
required String feedbackType,
|
||||
}) async {
|
||||
return _tendersService.feedback(
|
||||
tenderId: tenderId,
|
||||
feedbackType: feedbackType,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ part 'feedback_response.g.dart';
|
||||
abstract class FeedbackResponse with _$FeedbackResponse {
|
||||
const factory FeedbackResponse({
|
||||
@JsonKey(name: 'meta') required Meta? meta,
|
||||
@JsonKey(name: 'data') required List<FeedbackData>? data,
|
||||
@JsonKey(name: 'data') required FeedbackData? data,
|
||||
@JsonKey(name: 'error') required ErrorModel? error,
|
||||
required String? message,
|
||||
required bool? success,
|
||||
|
||||
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$FeedbackResponse {
|
||||
|
||||
@JsonKey(name: 'meta') Meta? get meta;@JsonKey(name: 'data') List<FeedbackData>? get data;@JsonKey(name: 'error') ErrorModel? get error; String? get message; bool? get success;
|
||||
@JsonKey(name: 'meta') Meta? get meta;@JsonKey(name: 'data') FeedbackData? get data;@JsonKey(name: 'error') ErrorModel? get error; String? get message; bool? get success;
|
||||
/// Create a copy of FeedbackResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -28,12 +28,12 @@ $FeedbackResponseCopyWith<FeedbackResponse> get copyWith => _$FeedbackResponseCo
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is FeedbackResponse&&(identical(other.meta, meta) || other.meta == meta)&&const DeepCollectionEquality().equals(other.data, data)&&(identical(other.error, error) || other.error == error)&&(identical(other.message, message) || other.message == message)&&(identical(other.success, success) || other.success == success));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is FeedbackResponse&&(identical(other.meta, meta) || other.meta == meta)&&(identical(other.data, data) || other.data == data)&&(identical(other.error, error) || other.error == error)&&(identical(other.message, message) || other.message == message)&&(identical(other.success, success) || other.success == success));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,meta,const DeepCollectionEquality().hash(data),error,message,success);
|
||||
int get hashCode => Object.hash(runtimeType,meta,data,error,message,success);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
@@ -48,11 +48,11 @@ abstract mixin class $FeedbackResponseCopyWith<$Res> {
|
||||
factory $FeedbackResponseCopyWith(FeedbackResponse value, $Res Function(FeedbackResponse) _then) = _$FeedbackResponseCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
@JsonKey(name: 'meta') Meta? meta,@JsonKey(name: 'data') List<FeedbackData>? data,@JsonKey(name: 'error') ErrorModel? error, String? message, bool? success
|
||||
@JsonKey(name: 'meta') Meta? meta,@JsonKey(name: 'data') FeedbackData? data,@JsonKey(name: 'error') ErrorModel? error, String? message, bool? success
|
||||
});
|
||||
|
||||
|
||||
$MetaCopyWith<$Res>? get meta;$ErrorModelCopyWith<$Res>? get error;
|
||||
$MetaCopyWith<$Res>? get meta;$FeedbackDataCopyWith<$Res>? get data;$ErrorModelCopyWith<$Res>? get error;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -69,7 +69,7 @@ class _$FeedbackResponseCopyWithImpl<$Res>
|
||||
return _then(_self.copyWith(
|
||||
meta: freezed == meta ? _self.meta : meta // ignore: cast_nullable_to_non_nullable
|
||||
as Meta?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable
|
||||
as List<FeedbackData>?,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as FeedbackData?,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as ErrorModel?,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?,
|
||||
@@ -91,6 +91,18 @@ $MetaCopyWith<$Res>? get meta {
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$FeedbackDataCopyWith<$Res>? get data {
|
||||
if (_self.data == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $FeedbackDataCopyWith<$Res>(_self.data!, (value) {
|
||||
return _then(_self.copyWith(data: value));
|
||||
});
|
||||
}/// Create a copy of FeedbackResponse
|
||||
/// 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;
|
||||
@@ -181,7 +193,7 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'meta') Meta? meta, @JsonKey(name: 'data') List<FeedbackData>? data, @JsonKey(name: 'error') ErrorModel? error, String? message, bool? success)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'meta') Meta? meta, @JsonKey(name: 'data') FeedbackData? data, @JsonKey(name: 'error') ErrorModel? error, String? message, bool? success)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FeedbackResponse() when $default != null:
|
||||
return $default(_that.meta,_that.data,_that.error,_that.message,_that.success);case _:
|
||||
@@ -202,7 +214,7 @@ return $default(_that.meta,_that.data,_that.error,_that.message,_that.success);c
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'meta') Meta? meta, @JsonKey(name: 'data') List<FeedbackData>? data, @JsonKey(name: 'error') ErrorModel? error, String? message, bool? success) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'meta') Meta? meta, @JsonKey(name: 'data') FeedbackData? data, @JsonKey(name: 'error') ErrorModel? error, String? message, bool? success) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FeedbackResponse():
|
||||
return $default(_that.meta,_that.data,_that.error,_that.message,_that.success);case _:
|
||||
@@ -222,7 +234,7 @@ return $default(_that.meta,_that.data,_that.error,_that.message,_that.success);c
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'meta') Meta? meta, @JsonKey(name: 'data') List<FeedbackData>? data, @JsonKey(name: 'error') ErrorModel? error, String? message, bool? success)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'meta') Meta? meta, @JsonKey(name: 'data') FeedbackData? data, @JsonKey(name: 'error') ErrorModel? error, String? message, bool? success)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FeedbackResponse() when $default != null:
|
||||
return $default(_that.meta,_that.data,_that.error,_that.message,_that.success);case _:
|
||||
@@ -237,19 +249,11 @@ return $default(_that.meta,_that.data,_that.error,_that.message,_that.success);c
|
||||
@JsonSerializable()
|
||||
|
||||
class _FeedbackResponse implements FeedbackResponse {
|
||||
const _FeedbackResponse({@JsonKey(name: 'meta') required this.meta, @JsonKey(name: 'data') required final List<FeedbackData>? data, @JsonKey(name: 'error') required this.error, required this.message, required this.success}): _data = data;
|
||||
const _FeedbackResponse({@JsonKey(name: 'meta') required this.meta, @JsonKey(name: 'data') required this.data, @JsonKey(name: 'error') required this.error, required this.message, required this.success});
|
||||
factory _FeedbackResponse.fromJson(Map<String, dynamic> json) => _$FeedbackResponseFromJson(json);
|
||||
|
||||
@override@JsonKey(name: 'meta') final Meta? meta;
|
||||
final List<FeedbackData>? _data;
|
||||
@override@JsonKey(name: 'data') List<FeedbackData>? get data {
|
||||
final value = _data;
|
||||
if (value == null) return null;
|
||||
if (_data is EqualUnmodifiableListView) return _data;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
@override@JsonKey(name: 'data') final FeedbackData? data;
|
||||
@override@JsonKey(name: 'error') final ErrorModel? error;
|
||||
@override final String? message;
|
||||
@override final bool? success;
|
||||
@@ -267,12 +271,12 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _FeedbackResponse&&(identical(other.meta, meta) || other.meta == meta)&&const DeepCollectionEquality().equals(other._data, _data)&&(identical(other.error, error) || other.error == error)&&(identical(other.message, message) || other.message == message)&&(identical(other.success, success) || other.success == success));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _FeedbackResponse&&(identical(other.meta, meta) || other.meta == meta)&&(identical(other.data, data) || other.data == data)&&(identical(other.error, error) || other.error == error)&&(identical(other.message, message) || other.message == message)&&(identical(other.success, success) || other.success == success));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,meta,const DeepCollectionEquality().hash(_data),error,message,success);
|
||||
int get hashCode => Object.hash(runtimeType,meta,data,error,message,success);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
@@ -287,11 +291,11 @@ abstract mixin class _$FeedbackResponseCopyWith<$Res> implements $FeedbackRespon
|
||||
factory _$FeedbackResponseCopyWith(_FeedbackResponse value, $Res Function(_FeedbackResponse) _then) = __$FeedbackResponseCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
@JsonKey(name: 'meta') Meta? meta,@JsonKey(name: 'data') List<FeedbackData>? data,@JsonKey(name: 'error') ErrorModel? error, String? message, bool? success
|
||||
@JsonKey(name: 'meta') Meta? meta,@JsonKey(name: 'data') FeedbackData? data,@JsonKey(name: 'error') ErrorModel? error, String? message, bool? success
|
||||
});
|
||||
|
||||
|
||||
@override $MetaCopyWith<$Res>? get meta;@override $ErrorModelCopyWith<$Res>? get error;
|
||||
@override $MetaCopyWith<$Res>? get meta;@override $FeedbackDataCopyWith<$Res>? get data;@override $ErrorModelCopyWith<$Res>? get error;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -307,8 +311,8 @@ class __$FeedbackResponseCopyWithImpl<$Res>
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? meta = freezed,Object? data = freezed,Object? error = freezed,Object? message = freezed,Object? success = freezed,}) {
|
||||
return _then(_FeedbackResponse(
|
||||
meta: freezed == meta ? _self.meta : meta // ignore: cast_nullable_to_non_nullable
|
||||
as Meta?,data: freezed == data ? _self._data : data // ignore: cast_nullable_to_non_nullable
|
||||
as List<FeedbackData>?,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as Meta?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable
|
||||
as FeedbackData?,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as ErrorModel?,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?,
|
||||
@@ -331,6 +335,18 @@ $MetaCopyWith<$Res>? get meta {
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$FeedbackDataCopyWith<$Res>? get data {
|
||||
if (_self.data == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $FeedbackDataCopyWith<$Res>(_self.data!, (value) {
|
||||
return _then(_self.copyWith(data: value));
|
||||
});
|
||||
}/// Create a copy of FeedbackResponse
|
||||
/// 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;
|
||||
|
||||
@@ -13,9 +13,9 @@ _FeedbackResponse _$FeedbackResponseFromJson(Map<String, dynamic> json) =>
|
||||
? null
|
||||
: Meta.fromJson(json['meta'] as Map<String, dynamic>),
|
||||
data:
|
||||
(json['data'] as List<dynamic>?)
|
||||
?.map((e) => FeedbackData.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
json['data'] == null
|
||||
? null
|
||||
: FeedbackData.fromJson(json['data'] as Map<String, dynamic>),
|
||||
error:
|
||||
json['error'] == null
|
||||
? null
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:tm_app/core/utils/logger.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/data/services/model/tenders/tender_dislike_response/tender_dislike_response.dart';
|
||||
import 'package:tm_app/data/services/model/tenders/tender_like_response/tender_like_response.dart';
|
||||
import 'package:tm_app/data/services/model/tenders/tender_reject_response/tender_reject_response.dart';
|
||||
import 'package:tm_app/data/services/model/tenders/tender_submit_response/tender_submit_response.dart';
|
||||
import 'package:tm_app/data/services/model/feedback_response/feedback_response.dart';
|
||||
import 'package:tm_app/data/services/model/tenders/tenders_response/tenders_response.dart';
|
||||
|
||||
import '../../core/network/network_manager.dart';
|
||||
@@ -14,106 +11,43 @@ class TendersService {
|
||||
: _networkManager = networkManager;
|
||||
final NetworkManager _networkManager;
|
||||
|
||||
Future<Result<TendersResponse>> getTenders() async {
|
||||
Future<Result<TendersResponse>> getTenders({
|
||||
required int limit,
|
||||
required int offset,
|
||||
}) async {
|
||||
final result = await _networkManager.makeRequest(
|
||||
'/api/v1/tenders',
|
||||
'/api/v1/tenders?limit=$limit&offset=$offset',
|
||||
method: 'GET',
|
||||
(json) => TendersResponse.fromJson(json),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<Result<TenderLikeResponse>> likeTender() async {
|
||||
try {
|
||||
// final result = await _networkManager.makeRequest(
|
||||
// '/api/v1/tenders',
|
||||
// (json) => TenderLikeResponse.fromJson(json),
|
||||
// method: 'POST',
|
||||
// );
|
||||
// await Future.delayed(Duration(seconds: 2));
|
||||
appLogger.info('like tender success');
|
||||
// TODO: will change when api is ready
|
||||
return Result.ok(
|
||||
TenderLikeResponse.fromJson({'message': 'Tender liked successfully'}),
|
||||
Future<Result<FeedbackResponse>> getTenderFeedback({
|
||||
required String tenderId,
|
||||
}) async {
|
||||
final result = await _networkManager.makeRequest(
|
||||
'/api/v1/feedback/tender/$tenderId',
|
||||
method: 'GET',
|
||||
(json) => FeedbackResponse.fromJson(json),
|
||||
);
|
||||
} on DioException catch (e) {
|
||||
appLogger.error('like tender failed: $e');
|
||||
return Result.error(e);
|
||||
} on Exception catch (e, stackTrace) {
|
||||
appLogger.error('like tender failed: $e', stackTrace: stackTrace);
|
||||
return Result.error(Exception(e));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<Result<TenderDislikeResponse>> dislikeTender() async {
|
||||
try {
|
||||
// final result = await _networkManager.makeRequest(
|
||||
// '/api/v1/tenders',
|
||||
// (json) => TenderDislikeResponse.fromJson(json),
|
||||
// method: 'POST',
|
||||
// );
|
||||
// await Future.delayed(Duration(seconds: 2));
|
||||
appLogger.info('dislike tender success');
|
||||
// TODO: will change when api is ready
|
||||
return Result.ok(
|
||||
TenderDislikeResponse.fromJson({
|
||||
'message': 'Tender disliked successfully',
|
||||
}),
|
||||
Future<Result<FeedbackResponse>> feedback({
|
||||
required String tenderId,
|
||||
required String feedbackType,
|
||||
}) async {
|
||||
final data = jsonEncode({
|
||||
'feedback_type': feedbackType,
|
||||
'tender_id': tenderId,
|
||||
});
|
||||
final result = await _networkManager.makeRequest(
|
||||
'/api/v1/feedback',
|
||||
method: 'POST',
|
||||
(json) => FeedbackResponse.fromJson(json),
|
||||
data: data,
|
||||
);
|
||||
} on DioException catch (e) {
|
||||
appLogger.error('dislike tender failed: $e');
|
||||
return Result.error(e);
|
||||
} on Exception catch (e, stackTrace) {
|
||||
appLogger.error('dislike tender failed: $e', stackTrace: stackTrace);
|
||||
return Result.error(Exception(e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<TenderSubmitResponse>> submitTender() async {
|
||||
try {
|
||||
// final result = await _networkManager.makeRequest(
|
||||
// '/api/v1/tenders',
|
||||
// (json) => TenderSubmitResponse.fromJson(json),
|
||||
// method: 'POST',
|
||||
// );
|
||||
// await Future.delayed(Duration(seconds: 2));
|
||||
appLogger.info('submit tender success');
|
||||
// TODO: will change when api is ready
|
||||
return Result.ok(
|
||||
TenderSubmitResponse.fromJson({
|
||||
'message': 'Tender submitted successfully',
|
||||
}),
|
||||
);
|
||||
} on DioException catch (e) {
|
||||
appLogger.error('submit tender failed: $e');
|
||||
return Result.error(e);
|
||||
} on Exception catch (e, stackTrace) {
|
||||
appLogger.error('submit tender failed: $e', stackTrace: stackTrace);
|
||||
return Result.error(Exception(e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<TenderRejectResponse>> rejectTender() async {
|
||||
try {
|
||||
// final result = await _networkManager.makeRequest(
|
||||
// '/api/v1/tenders',
|
||||
// (json) => TenderRejectResponse.fromJson(json),
|
||||
// method: 'POST',
|
||||
// );
|
||||
// await Future.delayed(Duration(seconds: 2));
|
||||
appLogger.info('reject tender success');
|
||||
// TODO: will change when api is ready
|
||||
return Result.ok(
|
||||
TenderRejectResponse.fromJson({
|
||||
'message': 'Tender rejected successfully',
|
||||
}),
|
||||
);
|
||||
} on DioException catch (e) {
|
||||
appLogger.error('reject tender failed: $e');
|
||||
return Result.error(e);
|
||||
} on Exception catch (e, stackTrace) {
|
||||
appLogger.error('reject tender failed: $e', stackTrace: stackTrace);
|
||||
return Result.error(Exception(e));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tm_app/data/repositories/tenders_repository.dart';
|
||||
import 'package:tm_app/data/services/model/tender/tender_model.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/tenders/tenders_response/tenders_response.dart';
|
||||
|
||||
import '../core/utils/result.dart';
|
||||
@@ -16,24 +19,61 @@ class TendersViewModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
bool _isLoading = false;
|
||||
bool _isLoadingMore = false;
|
||||
String? _errorMessage;
|
||||
TendersResponse? _tendersResponse;
|
||||
FeedbackData? _feedbackData;
|
||||
|
||||
bool get isLoading => _isLoading;
|
||||
bool get isLoadingMore => _isLoadingMore;
|
||||
String? get errorMessage => _errorMessage;
|
||||
TendersResponse? get tendersResponse => _tendersResponse;
|
||||
FeedbackData? get feedbackData => _feedbackData;
|
||||
|
||||
List<FeedbackData> feedbacks = [];
|
||||
|
||||
int currentPage = 1;
|
||||
int _currentOffset = 0;
|
||||
static const int _pageSize = 10;
|
||||
bool _hasMoreData = true;
|
||||
|
||||
bool get hasMoreData => _hasMoreData;
|
||||
|
||||
/// Get feedback for a specific tender
|
||||
FeedbackData? getFeedbackForTender(String tenderId) {
|
||||
try {
|
||||
return feedbacks.firstWhere((f) => f.tender == tenderId);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if feedback exists for a specific tender
|
||||
bool hasFeedbackForTender(String tenderId) {
|
||||
return feedbacks.any((f) => f.tender == tenderId);
|
||||
}
|
||||
|
||||
Future<void> getTenders() async {
|
||||
_isLoading = true;
|
||||
_errorMessage = null;
|
||||
_currentOffset = 0;
|
||||
_hasMoreData = true;
|
||||
notifyListeners();
|
||||
|
||||
final result = await _tendersRepository.getTenders();
|
||||
final result = await _tendersRepository.getTenders(
|
||||
limit: _pageSize,
|
||||
offset: _currentOffset,
|
||||
);
|
||||
switch (result) {
|
||||
case Ok<TendersResponse>():
|
||||
_tendersResponse = result.value;
|
||||
// Check if we have more data
|
||||
if (_tendersResponse?.data?.tenders != null) {
|
||||
_hasMoreData = _tendersResponse!.data!.tenders!.length >= _pageSize;
|
||||
}
|
||||
if (_tendersResponse?.data?.tenders?.isNotEmpty == true) {
|
||||
getTenderFeedback(_tendersResponse!.data!.tenders!.first.id!);
|
||||
}
|
||||
break;
|
||||
case Error<TendersResponse>():
|
||||
_errorMessage = result.error.toString();
|
||||
@@ -45,166 +85,121 @@ class TendersViewModel with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Updates a tender's state in the list
|
||||
void _updateTenderState(
|
||||
String tenderId, {
|
||||
bool? liked,
|
||||
bool? disliked,
|
||||
bool? rejected,
|
||||
bool? submitted,
|
||||
}) {
|
||||
// if (_tendersResponse?.tendersData?.tenders != null) {
|
||||
// final updatedTenders =
|
||||
// _tendersResponse!.tendersData!.tenders!.map((element) {
|
||||
// if (element.tenderId == tenderId) {
|
||||
// return element.copyWith(
|
||||
// liked: liked,
|
||||
// disliked: disliked,
|
||||
// rejected: rejected,
|
||||
// submitted: submitted,
|
||||
// );
|
||||
// }
|
||||
// return element;
|
||||
// }).toList();
|
||||
Future<void> loadMoreTenders() async {
|
||||
if (_isLoadingMore || !_hasMoreData) return;
|
||||
|
||||
// _tendersResponse = _tendersResponse!.copyWith(
|
||||
// tendersData: _tendersResponse!.tendersData!.copyWith(
|
||||
// tenders: updatedTenders,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
_isLoadingMore = true;
|
||||
_errorMessage = null;
|
||||
notifyListeners();
|
||||
|
||||
_currentOffset += _pageSize;
|
||||
final result = await _tendersRepository.getTenders(
|
||||
limit: _pageSize,
|
||||
offset: _currentOffset,
|
||||
);
|
||||
|
||||
switch (result) {
|
||||
case Ok<TendersResponse>():
|
||||
if (result.value.data?.tenders != null &&
|
||||
result.value.data!.tenders!.isNotEmpty) {
|
||||
// Create a new modifiable list by combining existing and new tenders
|
||||
if (_tendersResponse?.data?.tenders != null) {
|
||||
final existingTenders = _tendersResponse!.data!.tenders!;
|
||||
final newTenders = result.value.data!.tenders!;
|
||||
final combinedTenders = [...existingTenders, ...newTenders];
|
||||
|
||||
// Create a new TendersData with the combined list
|
||||
_tendersResponse = _tendersResponse!.copyWith(
|
||||
data: _tendersResponse!.data!.copyWith(tenders: combinedTenders),
|
||||
);
|
||||
} else {
|
||||
_tendersResponse = result.value;
|
||||
}
|
||||
// Check if we have more data
|
||||
_hasMoreData = result.value.data!.tenders!.length >= _pageSize;
|
||||
} else {
|
||||
_hasMoreData = false;
|
||||
}
|
||||
break;
|
||||
case Error<TendersResponse>():
|
||||
_errorMessage = result.error.toString();
|
||||
_currentOffset -= _pageSize; // Revert offset on error
|
||||
break;
|
||||
}
|
||||
|
||||
/// Sets a tender as liked
|
||||
Future<void> markLiked(TenderModel tender) async {
|
||||
// _updateTenderState(
|
||||
// tender.id!,
|
||||
// liked: true,
|
||||
// disliked: false,
|
||||
// rejected: false,
|
||||
// submitted: tender.submitted,
|
||||
// );
|
||||
// notifyListeners();
|
||||
// final result = await _tendersRepository.likeTender();
|
||||
// switch (result) {
|
||||
// case Ok<TenderLikeResponse>():
|
||||
// break;
|
||||
// case Error<TenderLikeResponse>():
|
||||
// break;
|
||||
// }
|
||||
_isLoadingMore = false;
|
||||
notifyListeners();
|
||||
_errorMessage = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Sets a tender as disliked
|
||||
Future<void> markDisliked(TenderModel tender) async {
|
||||
// _updateTenderState(
|
||||
// tender.tenderId!,
|
||||
// disliked: true,
|
||||
// liked: false,
|
||||
// rejected: tender.rejected,
|
||||
// submitted: false,
|
||||
// );
|
||||
// notifyListeners();
|
||||
// final result = await _tendersRepository.dislikeTender();
|
||||
// switch (result) {
|
||||
// case Ok<TenderDislikeResponse>():
|
||||
// break;
|
||||
// case Error<TenderDislikeResponse>():
|
||||
// break;
|
||||
// }
|
||||
Future<void> getTenderFeedback(String tenderId) async {
|
||||
// _isLoading = true;
|
||||
_errorMessage = null;
|
||||
notifyListeners();
|
||||
|
||||
final result = await _tendersRepository.getTenderFeedback(
|
||||
tenderId: tenderId,
|
||||
);
|
||||
switch (result) {
|
||||
case Ok<FeedbackResponse>():
|
||||
_feedbackData = result.value.data;
|
||||
// Add or update _feedbackData in feedbacks list by tender id
|
||||
if (_feedbackData != null) {
|
||||
final index = feedbacks.indexWhere(
|
||||
(f) => f.tender == _feedbackData!.tender,
|
||||
);
|
||||
if (index != -1) {
|
||||
feedbacks[index] = _feedbackData!;
|
||||
log('Updated feedback for tender: ${_feedbackData!.tender}');
|
||||
} else {
|
||||
feedbacks.add(_feedbackData!);
|
||||
log('Added new feedback for tender: ${_feedbackData!.tender}');
|
||||
}
|
||||
log('Total feedbacks: ${feedbacks.length}');
|
||||
}
|
||||
break;
|
||||
case Error<FeedbackResponse>():
|
||||
_errorMessage = result.error.toString();
|
||||
break;
|
||||
}
|
||||
// _isLoading = false;
|
||||
notifyListeners();
|
||||
_errorMessage = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Sets a tender as rejected
|
||||
Future<void> markRejected(TenderModel tender) async {
|
||||
// _updateTenderState(
|
||||
// tender.tenderId!,
|
||||
// rejected: true,
|
||||
// liked: false,
|
||||
// disliked: tender.disliked,
|
||||
// submitted: false,
|
||||
// );
|
||||
// notifyListeners();
|
||||
// final result = await _tendersRepository.rejectTender();
|
||||
// switch (result) {
|
||||
// case Ok<TenderRejectResponse>():
|
||||
// break;
|
||||
// case Error<TenderRejectResponse>():
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
Future<void> feedback({
|
||||
required String tenderId,
|
||||
required String feedbackType,
|
||||
}) async {
|
||||
_errorMessage = null;
|
||||
notifyListeners();
|
||||
|
||||
/// Sets a tender as submitted
|
||||
Future<void> markSubmitted(TenderModel tender) async {
|
||||
// _updateTenderState(
|
||||
// tender.tenderId!,
|
||||
// submitted: true,
|
||||
// liked: tender.liked,
|
||||
// disliked: false,
|
||||
// rejected: false,
|
||||
// );
|
||||
// notifyListeners();
|
||||
// final result = await _tendersRepository.submitTender();
|
||||
// switch (result) {
|
||||
// case Ok<TenderSubmitResponse>():
|
||||
// break;
|
||||
// case Error<TenderSubmitResponse>():
|
||||
// break;
|
||||
// }
|
||||
final result = await _tendersRepository.feedback(
|
||||
tenderId: tenderId,
|
||||
feedbackType: feedbackType,
|
||||
);
|
||||
switch (result) {
|
||||
case Ok<FeedbackResponse>():
|
||||
_feedbackData = result.value.data;
|
||||
if (_feedbackData != null) {
|
||||
final index = feedbacks.indexWhere(
|
||||
(f) => f.tender == _feedbackData!.tender,
|
||||
);
|
||||
if (index != -1) {
|
||||
feedbacks[index] = _feedbackData!;
|
||||
} else {
|
||||
feedbacks.add(_feedbackData!);
|
||||
}
|
||||
|
||||
/// Clears a specific state for a tender
|
||||
void clearTenderState(
|
||||
TenderModel tenderModel, {
|
||||
bool? isLiked,
|
||||
bool? isDisliked,
|
||||
bool? isRejected,
|
||||
bool? isSubmitted,
|
||||
}) {
|
||||
// _updateTenderState(
|
||||
// tenderModel.tenderId!,
|
||||
// liked: isLiked ?? tenderModel.liked,
|
||||
// disliked: isDisliked ?? tenderModel.disliked,
|
||||
// rejected: isRejected ?? tenderModel.rejected,
|
||||
// submitted: isSubmitted ?? tenderModel.submitted,
|
||||
// );
|
||||
}
|
||||
|
||||
/// Toggles like state for a tender
|
||||
void toggleLike(TenderModel tender) {
|
||||
// if (tender.liked == true) {
|
||||
// clearTenderState(tender, isLiked: false);
|
||||
// } else {
|
||||
// markLiked(tender);
|
||||
// }
|
||||
// notifyListeners();
|
||||
break;
|
||||
case Error<FeedbackResponse>():
|
||||
_errorMessage = result.error.toString();
|
||||
break;
|
||||
}
|
||||
|
||||
/// Toggles dislike state for a tender
|
||||
void toggleDislike(TenderModel tender) {
|
||||
// if (tender.disliked == true) {
|
||||
// clearTenderState(tender, isDisliked: false);
|
||||
// } else {
|
||||
// markDisliked(tender);
|
||||
// }
|
||||
// notifyListeners();
|
||||
}
|
||||
|
||||
/// Toggles reject state for a tender
|
||||
void toggleReject(TenderModel tender) {
|
||||
// if (tender.rejected == true) {
|
||||
// clearTenderState(tender, isRejected: false);
|
||||
// } else {
|
||||
// markRejected(tender);
|
||||
// }
|
||||
// notifyListeners();
|
||||
}
|
||||
|
||||
/// Toggles submit state for a tender
|
||||
void toggleSubmit(TenderModel tender) {
|
||||
// if (tender.submitted == true) {
|
||||
// clearTenderState(tender, isSubmitted: false);
|
||||
// } else {
|
||||
// markSubmitted(tender);
|
||||
// }
|
||||
// notifyListeners();
|
||||
notifyListeners();
|
||||
_errorMessage = null;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tm_app/core/theme/colors.dart';
|
||||
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
|
||||
import 'package:tm_app/view_models/tenders_view_model.dart';
|
||||
|
||||
import '../../../core/constants/assets.dart';
|
||||
import '../../../core/utils/size_config.dart';
|
||||
@@ -26,29 +28,45 @@ class _MainTendersSliderState extends State<MainTendersSlider> {
|
||||
int currentPage = 1;
|
||||
|
||||
void _goToPreviousPage() {
|
||||
if (currentPage == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
pageController.previousPage(
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOutCubic,
|
||||
);
|
||||
setState(() {
|
||||
if (currentPage == 1) {
|
||||
return;
|
||||
}
|
||||
currentPage = currentPage - 1;
|
||||
});
|
||||
|
||||
// Fetch feedback for the previous tender if not already loaded
|
||||
final viewModel = context.read<TendersViewModel>();
|
||||
final previousTenderId = widget.tenders[currentPage - 2].id!;
|
||||
if (!viewModel.hasFeedbackForTender(previousTenderId)) {
|
||||
viewModel.getTenderFeedback(previousTenderId);
|
||||
}
|
||||
}
|
||||
|
||||
void _goToNextPage() {
|
||||
if (currentPage == widget.tenders.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
pageController.nextPage(
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOutCubic,
|
||||
);
|
||||
setState(() {
|
||||
if (currentPage == widget.tenders.length) {
|
||||
return;
|
||||
}
|
||||
currentPage = currentPage + 1;
|
||||
});
|
||||
|
||||
// Fetch feedback for the next tender if not already loaded
|
||||
final viewModel = context.read<TendersViewModel>();
|
||||
final nextTenderId = widget.tenders[currentPage].id!;
|
||||
if (!viewModel.hasFeedbackForTender(nextTenderId)) {
|
||||
viewModel.getTenderFeedback(nextTenderId);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -76,6 +94,19 @@ class _MainTendersSliderState extends State<MainTendersSlider> {
|
||||
setState(() {
|
||||
currentPage = index + 1;
|
||||
});
|
||||
|
||||
// Fetch feedback for the new tender if not already loaded
|
||||
final viewModel = context.read<TendersViewModel>();
|
||||
if (!viewModel.hasFeedbackForTender(widget.tenders[index].id!)) {
|
||||
viewModel.getTenderFeedback(widget.tenders[index].id!);
|
||||
}
|
||||
|
||||
// Check if we need to load more tenders (when user reaches near the end)
|
||||
if (index >= widget.tenders.length - 1 &&
|
||||
viewModel.hasMoreData &&
|
||||
!viewModel.isLoadingMore) {
|
||||
viewModel.loadMoreTenders();
|
||||
}
|
||||
},
|
||||
itemBuilder: (context, index) {
|
||||
final tender = widget.tenders[index];
|
||||
@@ -119,13 +150,31 @@ class _MainTendersSliderState extends State<MainTendersSlider> {
|
||||
}
|
||||
|
||||
Widget _pageNumberText() {
|
||||
return Text(
|
||||
final viewModel = context.watch<TendersViewModel>();
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'$currentPage/${widget.tenders.length}',
|
||||
style: TextStyle(
|
||||
fontSize: 14.0.sp(),
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.grey,
|
||||
),
|
||||
),
|
||||
if (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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final viewModel = context.watch<TendersViewModel>();
|
||||
return Consumer<TendersViewModel>(
|
||||
builder: (context, viewModel, child) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
@@ -40,6 +41,8 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
_likeButton(viewModel),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _rejectButton(TendersViewModel viewModel) {
|
||||
@@ -154,12 +157,16 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _dislikeButton(TendersViewModel viewModel) {
|
||||
// Find feedback for this specific tender
|
||||
final feedback = viewModel.getFeedbackForTender(tender.id!);
|
||||
final isDisliked = feedback?.feedbackType == 'dislike';
|
||||
|
||||
return Tooltip(
|
||||
message: AppStrings.dislike,
|
||||
child: InkWell(
|
||||
splashColor: Colors.transparent,
|
||||
onTap: () {
|
||||
// viewModel.toggleDislike(tender);
|
||||
viewModel.feedback(tenderId: tender.id!, feedbackType: 'dislike');
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -169,10 +176,7 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
fit: BoxFit.cover,
|
||||
AssetsManager.dislike,
|
||||
colorFilter: ColorFilter.mode(
|
||||
// tender.disliked ?? false
|
||||
// ? AppColors.errorColor
|
||||
// :
|
||||
AppColors.grey50,
|
||||
isDisliked ? AppColors.errorColor : AppColors.grey50,
|
||||
BlendMode.srcATop,
|
||||
),
|
||||
),
|
||||
@@ -183,11 +187,7 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
// tender.disliked ?? false
|
||||
// ? AppColors.errorColor
|
||||
// :
|
||||
AppColors.grey50,
|
||||
color: isDisliked ? AppColors.errorColor : AppColors.grey50,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -197,12 +197,16 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _likeButton(TendersViewModel viewModel) {
|
||||
// Find feedback for this specific tender
|
||||
final feedback = viewModel.getFeedbackForTender(tender.id!);
|
||||
final isLiked = feedback?.feedbackType == 'like';
|
||||
|
||||
return Tooltip(
|
||||
message: AppStrings.like,
|
||||
child: InkWell(
|
||||
splashColor: Colors.transparent,
|
||||
onTap: () {
|
||||
// viewModel.toggleLike(tender);
|
||||
viewModel.feedback(tenderId: tender.id!, feedbackType: 'like');
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -212,10 +216,7 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
fit: BoxFit.cover,
|
||||
AssetsManager.like,
|
||||
colorFilter: ColorFilter.mode(
|
||||
// tender.liked ?? false
|
||||
// ? AppColors.successColor
|
||||
// :
|
||||
AppColors.grey50,
|
||||
isLiked ? AppColors.successColor : AppColors.grey50,
|
||||
BlendMode.srcATop,
|
||||
),
|
||||
),
|
||||
@@ -226,11 +227,7 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
// tender.liked ?? false
|
||||
// ? AppColors.successColor
|
||||
// :
|
||||
AppColors.grey50,
|
||||
color: isLiked ? AppColors.successColor : AppColors.grey50,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user