import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; class TokenStorageService { static final TokenStorageService _instance = TokenStorageService._internal(); factory TokenStorageService() => _instance; TokenStorageService._internal(); // Storage keys static const String _preEnrollmentKey = 'pre_enrollment_data'; static const String _postEnrollmentKey = 'post_enrollment_data'; static const String _selectedBranchKey = 'selected_branch'; static const String _decodedTokenKey = 'decoded_token'; // In-memory cache List? _preEnrollmentData; List? _postEnrollmentData; Map? _selectedBranch; Map? _decodedToken; // Initialize - Load data from storage Future initialize() async { final prefs = await SharedPreferences.getInstance(); final preData = prefs.getString(_preEnrollmentKey); if (preData != null) { _preEnrollmentData = json.decode(preData); } final postData = prefs.getString(_postEnrollmentKey); if (postData != null) { _postEnrollmentData = json.decode(postData); } final branchData = prefs.getString(_selectedBranchKey); if (branchData != null) { _selectedBranch = json.decode(branchData); } final tokenData = prefs.getString(_decodedTokenKey); if (tokenData != null) { _decodedToken = json.decode(tokenData); } } // Save enrollment data Future saveEnrollmentData(List preData, List postData) async { _preEnrollmentData = preData; _postEnrollmentData = postData; final prefs = await SharedPreferences.getInstance(); await prefs.setString(_preEnrollmentKey, json.encode(preData)); await prefs.setString(_postEnrollmentKey, json.encode(postData)); } // Get combined unique branches List> getCombinedBranches() { List> combined = []; Set seenTokens = {}; Set seenIds = {}; // Add pre-enrollment data if (_preEnrollmentData != null) { for (var item in _preEnrollmentData!) { String token = item['token']?.toString() ?? ''; String uniqueId = '${item['id']}_${item['client_id']}_${item['client_branch_id']}'; if (seenIds.contains(uniqueId)) continue; if (token.isNotEmpty && seenTokens.contains(token)) continue; if (token.isNotEmpty) seenTokens.add(token); seenIds.add(uniqueId); combined.add({...item, 'enrollment_type': 'pre'}); } } // Add post-enrollment data if (_postEnrollmentData != null) { for (var item in _postEnrollmentData!) { String token = item['token']?.toString() ?? ''; String uniqueId = '${item['id']}_${item['client_id']}_${item['client_branch_id']}'; if (seenIds.contains(uniqueId)) continue; if (token.isNotEmpty && seenTokens.contains(token)) continue; if (token.isNotEmpty) seenTokens.add(token); seenIds.add(uniqueId); combined.add({...item, 'enrollment_type': 'post'}); } } return combined; } // Save selected branch and decode token Future saveSelectedBranch(Map branch) async { _selectedBranch = branch; String token = branch['token']?.toString() ?? ''; if (token.isNotEmpty) { _decodedToken = _decodeJWT(token); } else { _decodedToken = null; } final prefs = await SharedPreferences.getInstance(); await prefs.setString(_selectedBranchKey, json.encode(branch)); if (_decodedToken != null) { await prefs.setString(_decodedTokenKey, json.encode(_decodedToken)); } } // Decode JWT token Map? _decodeJWT(String token) { try { final parts = token.split('.'); if (parts.length != 3) return null; final payload = parts[1]; var normalized = base64Url.normalize(payload); var decoded = utf8.decode(base64Url.decode(normalized)); return json.decode(decoded); } catch (e) { print('Error decoding token: $e'); return null; } } // Getters Map? getSelectedBranch() => _selectedBranch; Map? getDecodedToken() => _decodedToken; String? getCurrentToken() => _selectedBranch?['token']; bool isLoggedIn() { return _selectedBranch != null && _selectedBranch!['token'] != null && _selectedBranch!['token'].toString().isNotEmpty; } // Clear all data (logout) Future clearAll() async { _preEnrollmentData = null; _postEnrollmentData = null; _selectedBranch = null; _decodedToken = null; final prefs = await SharedPreferences.getInstance(); await prefs.remove(_preEnrollmentKey); await prefs.remove(_postEnrollmentKey); await prefs.remove(_selectedBranchKey); await prefs.remove(_decodedTokenKey); } }