tenders pagination added

This commit is contained in:
amirrezaghabeli
2025-08-19 08:08:31 +03:30
parent 0c1b27fd1e
commit da6b1f28cf
4 changed files with 111 additions and 13 deletions
@@ -8,8 +8,11 @@ class TendersRepository {
: _tendersService = tendersService; : _tendersService = tendersService;
final TendersService _tendersService; final TendersService _tendersService;
Future<Result<TendersResponse>> getTenders() async { Future<Result<TendersResponse>> getTenders({
return _tendersService.getTenders(); required int limit,
required int offset,
}) async {
return _tendersService.getTenders(limit: limit, offset: offset);
} }
Future<Result<FeedbackResponse>> getTenderFeedback({ Future<Result<FeedbackResponse>> getTenderFeedback({
+5 -2
View File
@@ -11,9 +11,12 @@ class TendersService {
: _networkManager = networkManager; : _networkManager = networkManager;
final 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( final result = await _networkManager.makeRequest(
'/api/v1/tenders', '/api/v1/tenders?limit=$limit&offset=$offset',
method: 'GET', method: 'GET',
(json) => TendersResponse.fromJson(json), (json) => TendersResponse.fromJson(json),
); );
+68 -2
View File
@@ -19,11 +19,13 @@ class TendersViewModel with ChangeNotifier {
} }
bool _isLoading = false; bool _isLoading = false;
bool _isLoadingMore = false;
String? _errorMessage; String? _errorMessage;
TendersResponse? _tendersResponse; TendersResponse? _tendersResponse;
FeedbackData? _feedbackData; FeedbackData? _feedbackData;
bool get isLoading => _isLoading; bool get isLoading => _isLoading;
bool get isLoadingMore => _isLoadingMore;
String? get errorMessage => _errorMessage; String? get errorMessage => _errorMessage;
TendersResponse? get tendersResponse => _tendersResponse; TendersResponse? get tendersResponse => _tendersResponse;
FeedbackData? get feedbackData => _feedbackData; FeedbackData? get feedbackData => _feedbackData;
@@ -31,6 +33,11 @@ class TendersViewModel with ChangeNotifier {
List<FeedbackData> feedbacks = []; List<FeedbackData> feedbacks = [];
int currentPage = 1; int currentPage = 1;
int _currentOffset = 0;
static const int _pageSize = 10;
bool _hasMoreData = true;
bool get hasMoreData => _hasMoreData;
/// Get feedback for a specific tender /// Get feedback for a specific tender
FeedbackData? getFeedbackForTender(String tenderId) { FeedbackData? getFeedbackForTender(String tenderId) {
@@ -49,13 +56,24 @@ class TendersViewModel with ChangeNotifier {
Future<void> getTenders() async { Future<void> getTenders() async {
_isLoading = true; _isLoading = true;
_errorMessage = null; _errorMessage = null;
_currentOffset = 0;
_hasMoreData = true;
notifyListeners(); notifyListeners();
final result = await _tendersRepository.getTenders(); final result = await _tendersRepository.getTenders(
limit: _pageSize,
offset: _currentOffset,
);
switch (result) { switch (result) {
case Ok<TendersResponse>(): case Ok<TendersResponse>():
_tendersResponse = result.value; _tendersResponse = result.value;
getTenderFeedback(_tendersResponse!.data!.tenders!.first.id!); // 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; break;
case Error<TendersResponse>(): case Error<TendersResponse>():
_errorMessage = result.error.toString(); _errorMessage = result.error.toString();
@@ -67,6 +85,54 @@ class TendersViewModel with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<void> loadMoreTenders() async {
if (_isLoadingMore || !_hasMoreData) return;
_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;
}
_isLoadingMore = false;
notifyListeners();
_errorMessage = null;
notifyListeners();
}
Future<void> getTenderFeedback(String tenderId) async { Future<void> getTenderFeedback(String tenderId) async {
// _isLoading = true; // _isLoading = true;
_errorMessage = null; _errorMessage = null;
@@ -94,11 +94,19 @@ class _MainTendersSliderState extends State<MainTendersSlider> {
setState(() { setState(() {
currentPage = index + 1; currentPage = index + 1;
}); });
// Fetch feedback for the new tender if not already loaded // Fetch feedback for the new tender if not already loaded
final viewModel = context.read<TendersViewModel>(); final viewModel = context.read<TendersViewModel>();
if (!viewModel.hasFeedbackForTender(widget.tenders[index].id!)) { if (!viewModel.hasFeedbackForTender(widget.tenders[index].id!)) {
viewModel.getTenderFeedback(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) { itemBuilder: (context, index) {
final tender = widget.tenders[index]; final tender = widget.tenders[index];
@@ -142,13 +150,31 @@ class _MainTendersSliderState extends State<MainTendersSlider> {
} }
Widget _pageNumberText() { Widget _pageNumberText() {
return Text( final viewModel = context.watch<TendersViewModel>();
'$currentPage/${widget.tenders.length}', return Column(
style: TextStyle( mainAxisSize: MainAxisSize.min,
fontSize: 14.0.sp(), children: [
fontWeight: FontWeight.w500, Text(
color: AppColors.grey, '$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,
),
),
),
],
); );
} }