marco.pms.mobileapp/lib/helpers/services/tenant_service.dart
2025-12-06 17:34:01 +05:30

155 lines
5.3 KiB
Dart

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:get/get.dart';
import 'package:on_field_work/controller/project_controller.dart';
import 'package:on_field_work/helpers/services/api_endpoints.dart';
import 'package:on_field_work/helpers/services/storage/local_storage.dart';
import 'package:on_field_work/helpers/services/app_logger.dart';
import 'package:on_field_work/helpers/services/auth_service.dart';
import 'package:on_field_work/model/tenant/tenant_list_model.dart';
import 'package:on_field_work/helpers/utils/encryption_helper.dart';
abstract class ITenantService {
Future<List<Map<String, dynamic>>?> getTenants({bool hasRetried = false});
Future<bool> selectTenant(String tenantId, {bool hasRetried = false});
}
class TenantService implements ITenantService {
static const String _baseUrl = ApiEndpoints.baseUrl;
static const Map<String, String> _headers = {
'Content-Type': 'application/json',
};
static Tenant? currentTenant;
static void setSelectedTenant(Tenant tenant) {
currentTenant = tenant;
}
static bool get isTenantSelected => currentTenant != null;
static Future<Map<String, String>> _authorizedHeaders() async {
final token = await LocalStorage.getJwtToken();
if (token == null || token.isEmpty) throw Exception('Missing JWT token');
return {..._headers, 'Authorization': 'Bearer $token'};
}
static void _handleApiError(http.Response response, dynamic data, String context) {
final message = data['message'] ?? 'Unknown error';
final level = response.statusCode >= 500 ? LogLevel.error : LogLevel.warning;
logSafe("$context failed: $message [Status: ${response.statusCode}]", level: level);
}
static void _logException(dynamic e, dynamic st, String context) {
logSafe("$context exception", level: LogLevel.error, error: e, stackTrace: st);
}
@override
Future<List<Map<String, dynamic>>?> getTenants({bool hasRetried = false}) async {
try {
final headers = await _authorizedHeaders();
final response = await http.get(Uri.parse("$_baseUrl/auth/get/user/tenants"), headers: headers);
if (response.body.isEmpty || response.body.trim().isEmpty) {
logSafe("❌ Empty tenant response — auto logout");
await LocalStorage.logout();
return null;
}
final decrypted = decryptResponse(response.body);
if (decrypted == null) {
logSafe("❌ Tenant response decryption failed — auto logout");
await LocalStorage.logout();
return null;
}
final data = decrypted is Map ? decrypted : null;
if (data == null) {
logSafe("❌ Decrypted tenant data is not valid JSON — auto logout");
await LocalStorage.logout();
return null;
}
if (response.statusCode == 200 && data['success'] == true) {
final list = data['data'];
if (list is! List) return null;
return List<Map<String, dynamic>>.from(list);
}
if (response.statusCode == 401 && !hasRetried) {
final refreshed = await AuthService.refreshToken();
if (refreshed) return getTenants(hasRetried: true);
return null;
}
_handleApiError(response, data, "Fetching tenants");
return null;
} catch (e, st) {
_logException(e, st, "Get Tenants API");
return null;
}
}
@override
Future<bool> selectTenant(String tenantId, {bool hasRetried = false}) async {
try {
final headers = await _authorizedHeaders();
logSafe("➡️ POST $_baseUrl/auth/select-tenant/$tenantId\nHeaders: $headers", level: LogLevel.info);
final response = await http.post(Uri.parse("$_baseUrl/auth/select-tenant/$tenantId"), headers: headers);
final decrypted = decryptResponse(response.body);
if (decrypted == null) {
logSafe("❌ Tenant selection response decryption failed", level: LogLevel.error);
return false;
}
final data = decrypted is Map ? decrypted : null;
if (data == null) {
logSafe("❌ Decrypted tenant selection data is not valid JSON", level: LogLevel.error);
return false;
}
logSafe("⬅️ Response: ${jsonEncode(data)} [Status: ${response.statusCode}]", level: LogLevel.info);
if (response.statusCode == 200 && data['success'] == true) {
await LocalStorage.setJwtToken(data['data']['token']);
await LocalStorage.setRefreshToken(data['data']['refreshToken']);
logSafe("✅ Tenant selected successfully. Tokens updated.");
try {
final projectController = Get.find<ProjectController>();
projectController.clearProjects();
projectController.fetchProjects();
} catch (_) {
logSafe("⚠️ ProjectController not found while refreshing projects");
}
final fcmToken = LocalStorage.getFcmToken();
if (fcmToken?.isNotEmpty ?? false) {
final success = await AuthService.registerDeviceToken(fcmToken!);
logSafe(success ? "✅ FCM token registered after tenant selection." : "⚠️ Failed to register FCM token.", level: success ? LogLevel.info : LogLevel.warning);
}
return true;
}
if (response.statusCode == 401 && !hasRetried) {
logSafe("⚠️ Unauthorized while selecting tenant. Refreshing token...", level: LogLevel.warning);
final refreshed = await AuthService.refreshToken();
if (refreshed) return selectTenant(tenantId, hasRetried: true);
logSafe("❌ Token refresh failed while selecting tenant.", level: LogLevel.error);
return false;
}
_handleApiError(response, data, "Selecting tenant");
return false;
} catch (e, st) {
_logException(e, st, "Select Tenant API");
return false;
}
}
}