displayed only accesable projects

This commit is contained in:
Vaibhav Surve 2025-05-05 13:09:59 +05:30
parent e6bba402ea
commit 3b7dfd09ff
4 changed files with 137 additions and 83 deletions

View File

@ -4,91 +4,97 @@ import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:marco/helpers/services/permission_service.dart';
import 'package:marco/model/user_permission.dart';
import 'package:marco/model/employee_info.dart'; // Import the EmployeeInfo model
import 'package:marco/model/employee_info.dart';
import 'package:marco/model/projects_model.dart';
class PermissionController extends GetxController {
var permissions = <UserPermission>[].obs;
var employeeInfo = Rxn<EmployeeInfo>(); // Observable for employee info
var employeeInfo = Rxn<EmployeeInfo>();
var projectsInfo = <ProjectInfo>[].obs;
Timer? _refreshTimer;
@override
@override
void onInit() {
super.onInit();
_loadDataFromAPI(); // Always fetch from API at start
_startAutoRefresh(); // Schedule auto-refresh
}
void onInit() {
super.onInit();
_loadDataFromAPI();
_startAutoRefresh();
}
// Save permissions and employee info to SharedPreferences
// Store all data at once to reduce redundant operations
Future<void> _storeData() async {
final prefs = await SharedPreferences.getInstance();
// Store permissions
final permissionsJson = permissions.map((e) => e.toJson()).toList();
print("Storing Permissions: $permissionsJson");
await prefs.setString('user_permissions', jsonEncode(permissionsJson));
await prefs.setString(
'user_permissions', jsonEncode(permissions.map((e) => e.toJson()).toList()));
// Store employee info
// Store employee info if available
if (employeeInfo.value != null) {
final employeeInfoJson = employeeInfo.value!.toJson();
print("Storing Employee Info: $employeeInfoJson");
await prefs.setString('employee_info', jsonEncode(employeeInfoJson));
await prefs.setString(
'employee_info', jsonEncode(employeeInfo.value!.toJson()));
}
// Store projects info if available
if (projectsInfo.isNotEmpty) {
await prefs.setString('projects_info',
jsonEncode(projectsInfo.map((e) => e.toJson()).toList()));
}
}
// Public method to load permissions and employee info (usually called from outside)
Future<void> loadData(String token) async {
try {
final result = await PermissionService.fetchPermissions(token);
print("Fetched Permissions from API: $result");
permissions.assignAll(result); // Update observable list
await _storeData(); // Cache locally
// Also fetch employee info from the API (you can extend the service if needed)
await _loadEmployeeInfoFromAPI(token);
} catch (e) {
print('Error loading data from API: $e');
}
}
// Internal helper to load token and fetch permissions and employee info from API
// Fetch and load all required data (permissions, employee info, and projects)
Future<void> _loadDataFromAPI() async {
final token = await _getAuthToken();
if (token != null && token.isNotEmpty) {
await loadData(token);
if (token?.isNotEmpty ?? false) {
await loadData(token!);
} else {
print("No token available for fetching data.");
}
}
// Retrieve token from SharedPreferences
Future<String?> _getAuthToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('jwt_token'); // Or 'auth_token' if thats the key you're using
// Fetch data and update the state (permissions, employee info, and projects)
Future<void> loadData(String token) async {
try {
final userData = await PermissionService.fetchAllUserData(token);
// Update state variables
_updateState(userData);
// Store all data after fetching
await _storeData();
} catch (e) {
print('Error loading data from API: $e');
}
}
// Auto-refresh every 30 minutes
// Update state variables (permissions, employeeInfo, and projects)
void _updateState(Map<String, dynamic> userData) {
permissions.assignAll(userData['permissions']);
employeeInfo.value = userData['employeeInfo'];
projectsInfo.assignAll(userData['projects']);
}
// Fetch the auth token from SharedPreferences
Future<String?> _getAuthToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('jwt_token');
}
// Set up automatic data refresh every 30 minutes
void _startAutoRefresh() {
_refreshTimer = Timer.periodic(Duration(minutes: 30), (timer) async {
await _loadDataFromAPI();
});
}
// Load employee info from the API
Future<void> _loadEmployeeInfoFromAPI(String token) async {
final employeeInfoResponse = await PermissionService.fetchEmployeeInfo(token);
print("Fetched Employee Info from API: $employeeInfoResponse");
employeeInfo.value = employeeInfoResponse; // Update observable employee info
await _storeData(); // Cache employee info locally
}
// Check for specific permission
// Check if the user has the given permission
bool hasPermission(String permissionId) {
return permissions.any((p) => p.id == permissionId);
}
bool isUserAssignedToProject(String projectId) {
return projectsInfo.any((project) => project.id == projectId);
}
@override
void onClose() {
_refreshTimer?.cancel();

View File

@ -1,53 +1,68 @@
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:marco/model/user_permission.dart';
import 'package:marco/model/employee_info.dart';
import 'package:marco/model/employee_info.dart';
import 'package:marco/model/projects_model.dart';
class PermissionService {
static Future<List<UserPermission>> fetchPermissions(String token) async {
// Cache to store the fetched user profile data per token
static final Map<String, Map<String, dynamic>> _userDataCache = {};
// Method to fetch the user profile data (permissions, employee info, and projects)
static Future<Map<String, dynamic>> fetchAllUserData(String token) async {
// Check if the data for this token is already cached
if (_userDataCache.containsKey(token)) {
return _userDataCache[token]!;
}
try {
// Fetch data from the API
final response = await http.get(
Uri.parse('https://stageapi.marcoaiot.com/api/user/profile'),
headers: {'Authorization': 'Bearer $token'},
);
if (response.statusCode == 200) {
final decoded = json.decode(response.body);
final List<dynamic> featurePermissions = decoded['data']['featurePermissions'];
final data = json.decode(response.body)['data'];
return featurePermissions
.map<UserPermission>((permissionId) => UserPermission.fromJson({'id': permissionId}))
.toList();
// Parse and extract relevant information
final permissions = _parsePermissions(data['featurePermissions']);
final employeeInfo = _parseEmployeeInfo(data['employeeInfo']);
final projectsInfo = _parseProjectsInfo(data['projects']);
// Cache the processed data for later use
final allUserData = {
'permissions': permissions,
'employeeInfo': employeeInfo,
'projects': projectsInfo,
};
_userDataCache[token] = allUserData;
return allUserData;
} else {
final errorData = json.decode(response.body);
throw Exception('Failed to load permissions: ${errorData['message']}');
throw Exception('Failed to load data: ${errorData['message']}');
}
} catch (e) {
print('Error fetching permissions: $e');
throw Exception('Error fetching permissions: $e');
print('Error fetching user data: $e');
throw Exception('Error fetching user data: $e');
}
}
// New method to fetch employee info
static Future<EmployeeInfo> fetchEmployeeInfo(String token) async {
try {
final response = await http.get(
Uri.parse('https://stageapi.marcoaiot.com/api/user/profile'),
headers: {'Authorization': 'Bearer $token'},
);
// Helper method to parse permissions from raw data
static List<UserPermission> _parsePermissions(List<dynamic> featurePermissions) {
return featurePermissions
.map<UserPermission>((id) => UserPermission.fromJson({'id': id}))
.toList();
}
if (response.statusCode == 200) {
final decoded = json.decode(response.body);
final employeeData = decoded['data']['employeeInfo'];
// Helper method to parse employee info from raw data
static EmployeeInfo _parseEmployeeInfo(Map<String, dynamic> employeeData) {
return EmployeeInfo.fromJson(employeeData);
}
return EmployeeInfo.fromJson(employeeData);
} else {
final errorData = json.decode(response.body);
throw Exception('Failed to load employee info: ${errorData['message']}');
}
} catch (e) {
print('Error fetching employee info: $e');
throw Exception('Error fetching employee info: $e');
}
// Helper method to parse projects from raw data
static List<ProjectInfo> _parseProjectsInfo(List<dynamic> projectIds) {
return projectIds.map<ProjectInfo>((id) => ProjectInfo.fromJson(id)).toList();
}
}

View File

@ -0,0 +1,15 @@
class ProjectInfo {
final String id;
ProjectInfo({required this.id});
// Deserialize from a string
factory ProjectInfo.fromJson(dynamic json) {
return ProjectInfo(id: json.toString());
}
// Serialize to a string
dynamic toJson() {
return id;
}
}

View File

@ -115,8 +115,26 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
)
];
}
return attendanceController.projects
.map((project) {
// Filter projects based on permissions
final accessibleProjects = attendanceController
.projects
.where((project) => permissionController
.isUserAssignedToProject(
project.id.toString()))
.toList();
if (accessibleProjects.isEmpty) {
return [
PopupMenuItem<String>(
value: '',
child: MyText.bodySmall(
'No Projects Assigned',
fontWeight: 600),
)
];
}
return accessibleProjects.map((project) {
return PopupMenuItem<String>(
value: project.id.toString(),
height: 32,
@ -138,7 +156,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
null
? attendanceController.projects
.firstWhereOrNull((proj) =>
proj.id==
proj.id ==
attendanceController
.selectedProjectId)
?.name ??
@ -861,7 +879,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
.captureAndUploadAttendance(
log.id,
log.employeeId,
attendanceController.selectedProjectId!,
attendanceController.selectedProjectId!,
comment: "Rejected",
action: 5, // Reject action
imageCapture: false,