import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:tm_app/core/utils/result.dart'; import 'package:tm_app/data/repositories/your_tenders_repository.dart'; import 'package:tm_app/data/services/model/liked_tenders_response/liked_tenders_response.dart'; import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart'; import 'package:tm_app/views/your_tenders/strings/your_tenders_strings.dart'; class YourTendersViewModel with ChangeNotifier { final YourTendersRepository yourTendersRepository; YourTendersViewModel({required this.yourTendersRepository}); bool isLoading = false; String? errorMessage; TenderApprovalsResponse? data; LikedTendersResponse? likedTendersData; // Pagination state for feedback lists bool isLoadingMore = false; bool hasMore = true; int _offset = 0; final int _limit = 10; String? _currentFeedbackType; // Pagination state for tenders bool isLoadingMoreTenders = false; bool hasMoreTenders = true; int _tendersOffset = 0; final int _tendersLimit = 10; // Filter States DateTimeRange? selectedDateRange; String selectedStatus = 'All'; final _fmt = DateFormat('yyyy/MM/dd'); String get startDateFormatted => selectedDateRange?.start != null ? _fmt.format(selectedDateRange!.start) : 'YYYY/MM/DD'; String get endDateFormatted => selectedDateRange?.end != null ? _fmt.format(selectedDateRange!.end) : 'YYYY/MM/DD'; String get startDateUnix => selectedDateRange?.start != null ? (selectedDateRange!.start.millisecondsSinceEpoch ~/ 1000).toString() : ''; String get endDateUnix => selectedDateRange?.end != null ? (selectedDateRange!.end.millisecondsSinceEpoch ~/ 1000).toString() : ''; Future getApprovedTenders({ required int limit, required int offset, bool reset = false, }) async { if (!reset && (isLoadingMoreTenders || !hasMoreTenders)) { return; } if (reset) { _tendersOffset = 0; hasMoreTenders = true; data = null; } if (_tendersOffset == 0) { isLoading = true; } else { isLoadingMoreTenders = true; } notifyListeners(); final result = await yourTendersRepository.getApprovedTenders( limit: _tendersLimit, offset: _tendersOffset, createdFrom: startDateUnix, createdTo: endDateUnix, ); switch (result) { case Ok(): final incoming = result.value; final incomingList = incoming.data?.tenders ?? []; if (reset || data == null) { data = incoming; } else { final existingList = data!.data?.tenders ?? []; final combined = List.of(existingList)..addAll(incomingList); final newMetadata = incoming.data?.metadata ?? data!.data?.metadata; data = data!.copyWith( data: data!.data!.copyWith( tenders: combined, metadata: newMetadata, ), ); } hasMoreTenders = incomingList.length == _tendersLimit; _tendersOffset += _tendersLimit; errorMessage = null; break; case Error(): errorMessage = result.error.toString(); break; } isLoading = false; isLoadingMoreTenders = false; notifyListeners(); } Future getTenders({ required int limit, required int offset, required String createdFrom, required String createdTo, bool reset = false, }) async { if (!reset && (isLoadingMoreTenders || !hasMoreTenders)) { return; } if (reset) { _tendersOffset = 0; hasMoreTenders = true; data = null; } if (_tendersOffset == 0) { isLoading = true; } else { isLoadingMoreTenders = true; } notifyListeners(); final result = await yourTendersRepository.getTenders( limit: _tendersLimit, offset: _tendersOffset, createdFrom: createdFrom, createdTo: createdTo, ); switch (result) { case Ok(): final incoming = result.value; final incomingList = incoming.data?.tenders ?? []; if (reset || data == null) { data = incoming; } else { final existingList = data!.data?.tenders ?? []; final combined = List.of(existingList)..addAll(incomingList); final newMetadata = incoming.data?.metadata ?? data!.data?.metadata; data = data!.copyWith( data: data!.data!.copyWith( tenders: combined, metadata: newMetadata, ), ); } hasMoreTenders = incomingList.length == _tendersLimit; _tendersOffset += _tendersLimit; errorMessage = null; break; case Error(): errorMessage = result.error.toString(); break; } isLoading = false; isLoadingMoreTenders = false; notifyListeners(); } Future getTendersFeedback({ required String feedbackType, bool reset = false, }) async { if (reset) { _offset = 0; hasMore = true; _currentFeedbackType = feedbackType; } if (!reset && (isLoadingMore || !hasMore)) { return; } if (_offset == 0) { isLoading = true; } else { isLoadingMore = true; } notifyListeners(); final result = await yourTendersRepository.getTendersFeedback( limit: _limit, offset: _offset, feedbackType: _currentFeedbackType ?? feedbackType, dateFrom: startDateUnix, dateTo: endDateUnix, ); switch (result) { case Ok(): final incoming = result.value; final incomingList = incoming.data?.feedback ?? []; if (reset || likedTendersData == null) { likedTendersData = incoming; } else { final existingList = likedTendersData!.data?.feedback ?? []; final combined = List.of(existingList)..addAll(incomingList); final newMeta = incoming.data?.meta ?? likedTendersData!.data?.meta; likedTendersData = likedTendersData!.copyWith( data: likedTendersData!.data!.copyWith( feedback: combined, meta: newMeta, ), ); } hasMore = incomingList.length == _limit; _offset += _limit; errorMessage = null; break; case Error(): errorMessage = result.error.toString(); break; } isLoading = false; isLoadingMore = false; notifyListeners(); } Future loadMoreFeedback() async { if (_currentFeedbackType == null) { return; } await getTendersFeedback(feedbackType: _currentFeedbackType!, reset: false); } Future loadMoreTenders() async { if (isLoadingMoreTenders || !hasMoreTenders) { return; } if (selectedStatus == YourTendersStrings.all) { await getTenders( limit: _tendersLimit, offset: _tendersOffset, createdFrom: startDateUnix, createdTo: endDateUnix, reset: false, ); } else if (selectedStatus == YourTendersStrings.tendersSubmitted) { await getApprovedTenders( limit: _tendersLimit, offset: _tendersOffset, reset: false, ); } } // --- Filter Actions --- void setDateRange(DateTimeRange? range) { selectedDateRange = range; notifyListeners(); } void setStatus(String status) { selectedStatus = status; notifyListeners(); } void clearFilter() { selectedDateRange = null; selectedStatus = YourTendersStrings.all; notifyListeners(); } Future callWithFilter() async { if (selectedStatus == YourTendersStrings.all) { await getTenders( limit: _tendersLimit, offset: 0, createdFrom: startDateUnix, createdTo: endDateUnix, reset: true, ); } else if (selectedStatus == YourTendersStrings.tendersSubmitted) { await getApprovedTenders(limit: _tendersLimit, offset: 0, reset: true); } else if (selectedStatus == YourTendersStrings.likeTenders) { await getTendersFeedback(feedbackType: 'like', reset: true); } else if (selectedStatus == YourTendersStrings.dislikeTenders) { await getTendersFeedback(feedbackType: 'dislike', reset: true); } } }