wesal/frontend/lib/services/invitations_service.dart

295 lines
9.4 KiB
Dart

import 'dart:convert';
import '../constants/api_constants.dart';
import '../models/invitation_models.dart';
import 'http_service.dart';
import 'auth_service.dart';
import 'cache_service.dart';
class InvitationsService {
static bool _pollingStarted = false;
/// Get all invitations with caching - returns cached data if available and fresh
static Future<Map<String, dynamic>> getAllInvitations({bool forceRefresh = false}) async {
// Return cached data if available and not forcing refresh
if (!forceRefresh) {
final cached = CacheService.getCached<InvitationsData>(CacheService.invitationsAllKey);
if (cached != null && !CacheService.isCacheExpired(CacheService.invitationsAllKey, CacheService.invitationsCacheDuration)) {
return {
'success': true,
'message': 'Loaded from cache',
'invitations': cached,
};
}
// Return stale data while fetching fresh data in background
final stale = CacheService.getCachedStale<InvitationsData>(CacheService.invitationsAllKey);
if (stale != null && !forceRefresh) {
// Trigger background refresh
_fetchAndCacheInvitations();
return {
'success': true,
'message': 'Loaded from cache (refreshing in background)',
'invitations': stale,
};
}
}
// Fetch fresh data
return await _fetchAndCacheInvitations();
}
static Future<Map<String, dynamic>> _fetchAndCacheInvitations([bool fromPolling = false]) async {
try {
final response = await HttpService.get(
ApiConstants.getAllInvitationsEndpoint,
);
if (response.statusCode == 200) {
final responseData = jsonDecode(response.body);
final invitationsResponse = InvitationsResponse.fromJson(responseData);
if (invitationsResponse.status) {
final invitationsData = invitationsResponse.data;
// Only cache when not called from polling to prevent conflicts
if (!fromPolling) {
CacheService.setCached(CacheService.invitationsAllKey, invitationsData);
}
return {
'success': true,
'invitations': invitationsData,
'message': invitationsResponse.message ?? '',
};
} else {
return {
'success': false,
'message': invitationsResponse.message ?? 'Failed to fetch invitations',
'invitations': InvitationsData(created: [], accepted: [], available: []),
};
}
} else if (response.statusCode == 401 || response.statusCode == 403) {
await AuthService.handleAuthenticationError();
return {
'success': false,
'message': 'Session expired. Please login again.',
'invitations': InvitationsData(created: [], accepted: [], available: []),
};
} else {
return {
'success': false,
'message': 'Server error (${response.statusCode})',
'invitations': InvitationsData(created: [], accepted: [], available: []),
};
}
} catch (e) {
print('Error fetching invitations: $e');
return {
'success': false,
'message': 'Network error. Please check your connection.',
'invitations': InvitationsData(created: [], accepted: [], available: []),
};
}
}
/// Start background polling for invitations
static void startPolling() {
_pollingStarted = true;
CacheService.startPolling(
CacheService.invitationsAllKey,
() => _fetchAndCacheInvitations(true), // Mark as from polling
CacheService.invitationsPollingInterval,
CacheService.invitationsCacheDuration,
);
}
/// Stop background polling for invitations
static void stopPolling() {
CacheService.stopPolling(CacheService.invitationsAllKey);
_pollingStarted = false;
}
/// Get invitations stream for real-time updates
static Stream<InvitationsData> getInvitationsStream() {
return CacheService.getStream<InvitationsData>(CacheService.invitationsAllKey);
}
/// Check if polling is active
static bool get isPollingActive => _pollingStarted;
/// Invalidate invitations cache (useful after creating/updating invitations)
static void invalidateCache() {
CacheService.clearCache(CacheService.invitationsAllKey);
}
static Future<Map<String, dynamic>> acceptInvitation(int invitationId) async {
try {
final response = await HttpService.post(
ApiConstants.acceptInvitationEndpoint,
{'id': invitationId},
);
if (response.statusCode == 200) {
final responseData = jsonDecode(response.body);
// Invalidate invitations cache since invitation status changed
invalidateCache();
return {
'success': responseData['status'] ?? false,
'message': responseData['message'] ?? 'Request completed',
};
} else if (response.statusCode == 401) {
return {
'success': false,
'message': 'Session expired. Please login again.',
};
} else if (response.statusCode == 403) {
return {
'success': false,
'message': 'Access denied. Invalid credentials.',
};
} else {
return {
'success': false,
'message': 'Server error (${response.statusCode})',
};
}
} catch (e) {
print('Error accepting invitation: $e');
return {
'success': false,
'message': 'Network error. Please check your connection.',
};
}
}
static Future<Map<String, dynamic>> createInvitation(Map<String, dynamic> invitationData) async {
try {
final response = await HttpService.post(
ApiConstants.createInvitationEndpoint,
invitationData,
);
if (response.statusCode == 200) {
final responseData = jsonDecode(response.body);
if (responseData['status'] == true) {
// Invalidate invitations cache since new invitation was created
invalidateCache();
return {
'success': true,
'data': responseData['data'],
'message': responseData['message'],
};
} else {
return {
'success': false,
'message': responseData['message'] ?? 'Failed to create invitation',
};
}
} else if (response.statusCode == 401) {
return {
'success': false,
'message': 'Session expired. Please login again.',
};
} else if (response.statusCode == 403) {
return {
'success': false,
'message': 'Access denied. Invalid credentials.',
};
} else {
return {
'success': false,
'message': 'Server error (${response.statusCode})',
};
}
} catch (e) {
print('Error creating invitation: $e');
return {
'success': false,
'message': 'Network error. Please check your connection.',
};
}
}
static Future<Map<String, dynamic>> getInvitationDetails(int invitationId) async {
try {
final response = await HttpService.get(
'${ApiConstants.invitationsEndpoint}/get?id=$invitationId',
);
if (response.statusCode == 200) {
final responseData = jsonDecode(response.body);
if (responseData['status'] == true) {
final invitationDetails = InvitationDetails.fromJson(responseData['data']);
return {
'success': true,
'data': invitationDetails,
};
} else {
return {
'success': false,
'message': responseData['message'] ?? 'Failed to get invitation details',
};
}
} else if (response.statusCode == 401) {
return {
'success': false,
'message': 'Session expired. Please login again.',
};
} else if (response.statusCode == 403) {
return {
'success': false,
'message': 'Access denied. Invalid credentials.',
};
} else {
return {
'success': false,
'message': 'Server error (${response.statusCode})',
};
}
} catch (e) {
print('Error getting invitation details: $e');
return {
'success': false,
'message': 'Network error. Please check your connection.',
};
}
}
static Future<Map<String, dynamic>> cancelInvitation(int invitationId) async {
try {
final response = await HttpService.post(
'${ApiConstants.invitationsEndpoint}/cancel',
{'id': invitationId},
);
if (response.statusCode == 200) {
final responseData = jsonDecode(response.body);
return {
'success': responseData['status'] ?? false,
'message': responseData['message'] ?? 'Request completed',
};
} else if (response.statusCode == 401) {
return {
'success': false,
'message': 'Session expired. Please login again.',
};
} else if (response.statusCode == 403) {
return {
'success': false,
'message': 'Access denied. Invalid credentials.',
};
} else {
return {
'success': false,
'message': 'Server error (${response.statusCode})',
};
}
} catch (e) {
print('Error canceling invitation: $e');
return {
'success': false,
'message': 'Network error. Please check your connection.',
};
}
}
}