You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cloudsolutions-atoms/lib/modules/site_request_module/providers/site_request_provider.dart

349 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/modules/site_request_module/models/dropdown_models.dart';
import 'package:test_sa/modules/site_request_module/models/request_type_model.dart';
import 'package:test_sa/modules/site_request_module/models/site_request_model.dart';
import 'package:test_sa/models/lookup.dart';
import 'dart:convert';
import 'package:http/http.dart';
/// Provider for managing site request operations including:
/// - Fetching request types
/// - Managing user's current sites
/// - Submitting site requests
/// - Fetching and paginating request history
class SiteRequestProvider extends ChangeNotifier {
// Constants
static const int _defaultPageSize = 10;
static const String _errorFetchFailed = 'Failed to fetch data';
static const String _errorSubmitFailed = 'Failed to submit request';
// Loading states
bool _loading = false;
bool _isLoadingMore = false;
// Data
List<RequestTypeModel> _requestTypes = [];
List<SiteRequestSiteModel> _userCurrentSites = [];
List<SiteRequestModel> _requestHistory = [];
// Pagination
int _currentPage = 1;
int _pageSize = _defaultPageSize;
bool _hasMoreData = true;
// Error handling
String? _errorMessage;
int? stateCode;
// Getters
bool get loading => _loading;
bool get isLoadingMore => _isLoadingMore;
String? get errorMessage => _errorMessage;
int get currentPage => _currentPage;
bool get hasMoreData => _hasMoreData;
List<RequestTypeModel> get requestTypes => _requestTypes;
List<SiteRequestSiteModel> get userCurrentSites => _userCurrentSites;
List<SiteRequestModel> get requestHistory => _requestHistory;
// User helper methods
String getCurrentUserEmployeeId(UserProvider userProvider) => userProvider.user?.userID ?? '';
String getCurrentUserFullName(UserProvider userProvider) => userProvider.user?.username ?? '';
String getCurrentUserEmail(UserProvider userProvider) => userProvider.user?.email ?? '';
String getCurrentUserMobile(UserProvider userProvider) => userProvider.user?.phoneNumber ?? '';
String getCurrentUserExtension(UserProvider userProvider) => userProvider.user?.extensionNo ?? '';
String getCurrentUserRole(UserProvider userProvider) {
if (userProvider.user?.userRoles != null && userProvider.user!.userRoles!.isNotEmpty) {
return userProvider.user!.userRoles!.first.name ?? '';
}
return '';
}
List<String> getCurrentUserAssignedSites(UserProvider userProvider) => [];
bool hasAssignedSites(List<String> assignedSites) => assignedSites.isNotEmpty;
// Setter
set loading(bool value) {
_loading = value;
notifyListeners();
}
/// Fetches available request types from the server
Future<int> fetchRequestTypes() async {
if (_loading) return -2;
return _performApiCall(
apiCall: () => ApiManager.instance.get(URLs.getSiteRequestTypes, enableToastMessage: false),
onSuccess: (responseData) {
List listJson = responseData['data'] ?? responseData;
_requestTypes = listJson
.map((item) => Lookup.fromJson(item))
.map((lookup) => RequestTypeModel(
id: lookup.id?.toString() ?? lookup.value?.toString() ?? '',
name: lookup.name ?? '',
value: lookup.value,
))
.toList();
},
errorMessage: 'Failed to fetch request types',
);
}
/// Fetches user's current sites for Change/Remove Site operations
Future<int> fetchUserCurrentSites(String userId) async {
if (_loading) return -2;
return _performApiCall(
apiCall: () => ApiManager.instance.post(URLs.getUserSites(userId), showToast: false, body: {}),
onSuccess: (responseData) {
List listJson = responseData['data'] ?? [];
_userCurrentSites = listJson
.map((item) => SiteRequestSiteModel(
id: item['siteId']?.toString() ?? '',
name: item['siteName'] ?? '',
))
.toList();
},
errorMessage: 'Failed to fetch user sites',
);
}
/// Submits a site request to the server
Future<bool> submitSiteRequest(SiteRequestModel request, UserProvider userProvider) async {
loading = true;
_errorMessage = null;
notifyListeners();
try {
final isChangeSiteRequest = _requestTypes.any((type) =>
type.identifier == request.requestType && (type.name?.toLowerCase().contains('change') ?? false));
final requestBody = _buildRequestBody(request, userProvider, isChangeSiteRequest);
final response = await ApiManager.instance.post(URLs.submitSiteRequest, body: requestBody);
if (response.statusCode >= 200 && response.statusCode < 300) {
_handleSubmitSuccess(response, request);
return true;
} else {
_handleSubmitError(response);
return false;
}
} catch (error) {
_errorMessage = '$_errorSubmitFailed: $error';
loading = false;
notifyListeners();
return false;
}
}
/// Fetches paginated site requests
Future<void> fetchSiteRequests({
int? pageSize,
int? pageNumber,
bool loadMore = false,
required UserProvider userProvider,
}) async {
final size = pageSize ?? _pageSize;
final page = pageNumber ?? (loadMore ? _currentPage + 1 : 1);
if (size <= 0 || page < 1) {
_errorMessage = 'Invalid pagination parameters';
notifyListeners();
return;
}
_setLoadingState(loadMore);
try {
final response = await ApiManager.instance.post(
URLs.getSiteRequests,
body: {
"pageSize": size,
"pageNumber": page,
"userId": getCurrentUserEmployeeId(userProvider),
},
);
if (response.statusCode == 200) {
_handleFetchSuccess(response, page, size, loadMore);
} else {
_errorMessage = _errorFetchFailed;
}
} catch (e) {
_errorMessage = 'Error: ${e.toString()}';
} finally {
_resetLoadingState();
}
}
/// Loads more site requests (pagination)
Future<void> loadMoreSiteRequests({required UserProvider userProvider}) async {
if (!_hasMoreData || _isLoadingMore) return;
await fetchSiteRequests(loadMore: true, userProvider: userProvider);
}
/// Refreshes site requests (resets to first page)
Future<void> refreshSiteRequests({required UserProvider userProvider}) async {
await fetchSiteRequests(pageNumber: 1, pageSize: _pageSize, userProvider: userProvider);
}
/// Resets provider state
void reset() {
_loading = false;
_errorMessage = null;
_requestHistory.clear();
notifyListeners();
}
// Private helper methods
/// Generic API call handler to reduce duplication
Future<int> _performApiCall({
required Future<Response> Function() apiCall,
required void Function(dynamic) onSuccess,
required String errorMessage,
}) async {
_loading = true;
_errorMessage = null;
notifyListeners();
try {
final response = await apiCall();
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
final responseData = json.decode(response.body);
onSuccess(responseData);
} else {
_errorMessage = errorMessage;
}
_loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
_loading = false;
stateCode = -1;
_errorMessage = errorMessage;
notifyListeners();
return -1;
}
}
Map<String, dynamic> _buildRequestBody(
SiteRequestModel request,
UserProvider userProvider,
bool isChangeSiteRequest,
) {
final siteIdsArray = request.siteIds.asMap().entries.map((entry) {
final index = entry.key;
return {
"id": 0,
"siteId": int.tryParse(request.siteIds[index]) ?? 0,
"siteName": request.siteNames[index],
"oldSiteId": (isChangeSiteRequest &&
request.oldSiteIds != null &&
index < request.oldSiteIds!.length)
? int.tryParse(request.oldSiteIds![index]) ?? 0
: 0,
"oldSitName": (isChangeSiteRequest &&
request.oldSiteNames != null &&
index < request.oldSiteNames!.length)
? request.oldSiteNames![index]
: ""
};
}).toList();
final departmentIdsArray = (request.departmentIds != null && request.departmentIds!.isNotEmpty)
? request.departmentIds!.asMap().entries.map((entry) {
return {
"id": 0,
"departmentId": int.tryParse(request.departmentIds![entry.key]) ?? 0,
"departmentName": request.departmentNames![entry.key],
};
}).toList()
: [];
return {
"id": 0,
"userId": getCurrentUserEmployeeId(userProvider),
"requestTypeId": int.tryParse(request.requestType) ?? 0,
"siteIds": siteIdsArray,
"departmentIds": departmentIdsArray,
};
}
void _handleSubmitSuccess(Response response, SiteRequestModel request) {
try {
final responseData = json.decode(response.body);
final requestWithId = request.copyWith(
id: responseData['id']?.toString() ?? 'REQ_${DateTime.now().millisecondsSinceEpoch}',
status: responseData['status']?.toString() ?? 'Pending',
requestDate: DateTime.now(),
);
_requestHistory.insert(0, requestWithId);
} catch (e) {
_errorMessage = 'Request submitted but failed to parse response';
} finally {
loading = false;
notifyListeners();
}
}
void _handleSubmitError(Response response) {
try {
final errorData = json.decode(response.body);
_errorMessage = errorData['message'] ?? _errorSubmitFailed;
} catch (e) {
_errorMessage = _errorSubmitFailed;
}
loading = false;
notifyListeners();
}
void _setLoadingState(bool loadMore) {
if (loadMore) {
_isLoadingMore = true;
} else {
loading = true;
_currentPage = 1;
_hasMoreData = true;
_requestHistory.clear();
}
_errorMessage = null;
notifyListeners();
}
void _handleFetchSuccess(Response response, int page, int size, bool loadMore) {
final data = json.decode(response.body);
if (data['isSuccess'] == true) {
final siteRequests = (data['data'] as List?)
?.map((item) => SiteRequestModel.fromJson(item))
.toList() ?? [];
if (loadMore) {
_requestHistory.addAll(siteRequests);
} else {
_requestHistory.clear();
_requestHistory.addAll(siteRequests);
}
_currentPage = page;
_hasMoreData = siteRequests.length >= size;
} else {
_errorMessage = data['message'] ?? _errorFetchFailed;
}
}
void _resetLoadingState() {
loading = false;
_isLoadingMore = false;
notifyListeners();
}
}