import 'package:flutter/material.dart'; import 'package:tm_app/core/utils/result.dart'; import 'package:tm_app/data/repositories/liked_tenders_repository.dart'; import 'package:tm_app/data/repositories/tenders_repository.dart'; import 'package:tm_app/data/services/model/liked_tender_feedback/liked_tender_feedback.dart'; import 'package:tm_app/data/services/model/liked_tenders_response/liked_tenders_response.dart'; import 'package:tm_app/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart'; import 'package:tm_app/view_models/home_view_model.dart'; import '../data/services/model/feedback_response/feedback_response.dart'; import '../data/services/model/request_models/tender_feedback_request_model/tender_feedback_request_model.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 LikedTendersViewModel with ChangeNotifier { final LikedTendersRepository _likedTendersRepository; final TendersRepository _tendersRepository; final HomeViewModel _homeViewModel; LikedTendersViewModel({ required LikedTendersRepository likedTendersRepository, required TendersRepository tendersRepository, required HomeViewModel homeViewModel, }) : _likedTendersRepository = likedTendersRepository, _homeViewModel = homeViewModel, _tendersRepository = tendersRepository; bool isLoading = false; bool isLoadingMore = false; bool hasMore = true; String? errorMessage; LikedTendersResponse? data; TenderApprovalsData? _tenderApprovalData; TenderApprovalsData? get tenderApprovalData => _tenderApprovalData; List tenderApprovals = []; int _offset = 0; final int _limit = 7; int currentPage = 1; // Approval status properties bool approvalStatus = false; String _status = ''; String? _errorMessage; bool _isSubmitApprovalLoading = false; bool _isRejectApprovalLoading = false; String get status => _status; String? get approvalErrorMessage => _errorMessage; bool get isSubmitApprovalLoading => _isSubmitApprovalLoading; bool get isRejectApprovalLoading => _isRejectApprovalLoading; void updateHome() { _homeViewModel.init(); } void clearApprovalErrorMessage() { _errorMessage = null; notifyListeners(); } Future getLikedTenders({bool reset = false}) async { if (!reset && (isLoadingMore || !hasMore)) { return; } if (reset) { _offset = (currentPage - 1) * _limit; hasMore = true; data = null; isLoading = true; notifyListeners(); } else { if (_offset == 0) { isLoading = true; } else { isLoadingMore = true; } notifyListeners(); } errorMessage = null; final requestModel = TenderFeedbackRequestModel( offset: _offset, limit: _limit, feedbackType: 'like', ); final result = await _likedTendersRepository.getLikedTenders( requestModel: requestModel, ); switch (result) { case Ok(): final incoming = result.value; final incomingList = incoming.data?.feedback ?? []; for (var element in incomingList) { await getTenderApproval(element.tenderId!); } if (reset) { data = incoming; } else { final existingList = data?.data?.feedback ?? []; final combined = List.of(existingList) ..addAll(incomingList); data = data?.copyWith( data: data?.data?.copyWith( feedback: combined, meta: incoming.data?.meta ?? data!.data!.meta, ), ); } hasMore = incomingList.length == _limit; _offset += _limit; errorMessage = null; break; case Error(): errorMessage = result.error.toString(); break; } isLoading = false; isLoadingMore = false; notifyListeners(); } Future loadMoreIfNeeded() async { if (isLoadingMore || !hasMore) { return; } await getLikedTenders(reset: false); } Future jumpToPage(int page) async { currentPage = page; _offset = (page - 1) * _limit; hasMore = true; await getLikedTenders(reset: true); } void removeTenderById(String id) async { final current = data; final list = current?.data?.feedback; if (current == null || list == null) { return; } // Store original list to restore if error occurs final originalList = List.of(list); final updatedList = List.of(list) ..removeWhere((e) => e.tenderId == id); // Temporarily update UI data = current.copyWith( data: current.data?.copyWith(feedback: updatedList), ); notifyListeners(); final result = await _tendersRepository.toggleFeedback( tenderId: id, feedbackType: 'like', ); switch (result) { case Ok(): final updatedMeta = current.data?.meta?.copyWith( total: updatedList.length, ); data = current.copyWith( data: current.data?.copyWith( feedback: updatedList, meta: updatedMeta, ), ); break; case Error(): // Restore original list if error occurs data = current.copyWith( data: current.data?.copyWith(feedback: originalList), ); errorMessage = result.error.toString(); break; } notifyListeners(); } Future getTenderApproval(String tenderId) async { errorMessage = null; notifyListeners(); final result = await _tendersRepository.getTenderApprovals( tenderId: tenderId, ); switch (result) { case Ok(): _tenderApprovalData = result.value.data; tenderApprovals.add(_tenderApprovalData!); break; case Error(): errorMessage = result.error.toString(); break; } notifyListeners(); errorMessage = null; notifyListeners(); } TenderApprovalsData? getApprovalStatusForTender(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 tender safely String? getApprovalStatusForTenderId(String tenderId) { try { final approval = tenderApprovals.firstWhere( (a) => a.tenderId == tenderId, ); return approval.status; } catch (e) { return null; } } /// Check if tender is submitted bool isTenderSubmitted(String tenderId) { return getApprovalStatusForTenderId(tenderId) == 'submitted'; } /// Check if tender is rejected bool isTenderRejected(String tenderId) { return getApprovalStatusForTenderId(tenderId) == 'rejected'; } Future submitTenderApproval({ required String tenderId, required String submissionMode, }) async { _isSubmitApprovalLoading = true; _errorMessage = null; notifyListeners(); // Store original state for rollback final originalApprovals = List.of(tenderApprovals); // Check current approval status and update optimistically final existingApproval = getApprovalStatusForTender(tenderId); if (existingApproval != null) { if (existingApproval.status == 'submitted') { // Remove from list if already submitted tenderApprovals.removeWhere((a) => a.tenderId == tenderId); } else if (existingApproval.status == 'rejected') { // Change rejected to submitted final updatedApproval = existingApproval.copyWith(status: 'submitted'); final index = tenderApprovals.indexWhere((a) => a.tenderId == tenderId); if (index != -1) { tenderApprovals[index] = updatedApproval; } } } else { // Add new approval with submitted status final newApproval = TenderApprovalsData( id: null, status: 'submitted', tenderId: tenderId, companyId: null, submissionMode: submissionMode, createdAt: null, tender: null, ); tenderApprovals.add(newApproval); } notifyListeners(); // Make server request final result = await _tendersRepository.toggleApprovals( tenderId: tenderId, status: 'submitted', submissionMode: submissionMode, ); switch (result) { case Ok(): approvalStatus = true; _status = result.value.data?.status ?? ''; break; case Error(): // Rollback changes on error tenderApprovals = originalApprovals; _errorMessage = result.error.toString(); approvalStatus = false; break; } approvalStatus = false; _isSubmitApprovalLoading = false; notifyListeners(); } Future rejectTenderApproval({ required String tenderId, required String submissionMode, }) async { _isRejectApprovalLoading = true; _errorMessage = null; notifyListeners(); // Store original state for rollback final originalApprovals = List.of(tenderApprovals); // Check current approval status and update optimistically final existingApproval = getApprovalStatusForTender(tenderId); if (existingApproval != null) { if (existingApproval.status == 'rejected') { // Remove from list if already rejected tenderApprovals.removeWhere((a) => a.tenderId == tenderId); } else if (existingApproval.status == 'submitted') { // Change submitted to rejected final updatedApproval = existingApproval.copyWith(status: 'rejected'); final index = tenderApprovals.indexWhere((a) => a.tenderId == tenderId); if (index != -1) { tenderApprovals[index] = updatedApproval; } } } else { // Add new approval with rejected status final newApproval = TenderApprovalsData( id: null, status: 'rejected', tenderId: tenderId, companyId: null, submissionMode: submissionMode, createdAt: null, tender: null, ); tenderApprovals.add(newApproval); } notifyListeners(); // Make server request final result = await _tendersRepository.toggleApprovals( tenderId: tenderId, status: 'rejected', submissionMode: submissionMode, ); switch (result) { case Ok(): approvalStatus = true; _status = result.value.data?.status ?? ''; break; case Error(): // Rollback changes on error tenderApprovals = originalApprovals; _errorMessage = result.error.toString(); approvalStatus = false; break; } approvalStatus = false; _isRejectApprovalLoading = false; notifyListeners(); } }