157 lines
4.8 KiB
Dart
157 lines
4.8 KiB
Dart
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<dynamic>? _preEnrollmentData;
|
|
List<dynamic>? _postEnrollmentData;
|
|
Map<String, dynamic>? _selectedBranch;
|
|
Map<String, dynamic>? _decodedToken;
|
|
|
|
// Initialize - Load data from storage
|
|
Future<void> 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<void> saveEnrollmentData(List<dynamic> preData, List<dynamic> 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<Map<String, dynamic>> getCombinedBranches() {
|
|
List<Map<String, dynamic>> combined = [];
|
|
Set<String> seenTokens = {};
|
|
Set<String> 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<void> saveSelectedBranch(Map<String, dynamic> 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<String, dynamic>? _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<String, dynamic>? getSelectedBranch() => _selectedBranch;
|
|
Map<String, dynamic>? getDecodedToken() => _decodedToken;
|
|
String? getCurrentToken() => _selectedBranch?['token'];
|
|
|
|
bool isLoggedIn() {
|
|
return _selectedBranch != null &&
|
|
_selectedBranch!['token'] != null &&
|
|
_selectedBranch!['token'].toString().isNotEmpty;
|
|
}
|
|
|
|
// Clear all data (logout)
|
|
Future<void> 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);
|
|
}
|
|
} |