From 3b7dfd09ffb49e1b275f70c798391ceabe48f515 Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Mon, 5 May 2025 13:09:59 +0530 Subject: [PATCH] displayed only accesable projects --- lib/controller/permission_controller.dart | 106 ++++++++++--------- lib/helpers/services/permission_service.dart | 73 ++++++++----- lib/model/projects_model.dart | 15 +++ lib/view/dashboard/attendanceScreen.dart | 26 ++++- 4 files changed, 137 insertions(+), 83 deletions(-) create mode 100644 lib/model/projects_model.dart diff --git a/lib/controller/permission_controller.dart b/lib/controller/permission_controller.dart index 590543a..385384d 100644 --- a/lib/controller/permission_controller.dart +++ b/lib/controller/permission_controller.dart @@ -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 = [].obs; - var employeeInfo = Rxn(); // Observable for employee info + var employeeInfo = Rxn(); + var projectsInfo = [].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 _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 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 _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 _getAuthToken() async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getString('jwt_token'); // Or 'auth_token' if that’s the key you're using + // Fetch data and update the state (permissions, employee info, and projects) + Future 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 userData) { + permissions.assignAll(userData['permissions']); + employeeInfo.value = userData['employeeInfo']; + projectsInfo.assignAll(userData['projects']); + } + + // Fetch the auth token from SharedPreferences + Future _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 _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(); diff --git a/lib/helpers/services/permission_service.dart b/lib/helpers/services/permission_service.dart index 620d2bf..545e597 100644 --- a/lib/helpers/services/permission_service.dart +++ b/lib/helpers/services/permission_service.dart @@ -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> fetchPermissions(String token) async { + // Cache to store the fetched user profile data per token + static final Map> _userDataCache = {}; + + // Method to fetch the user profile data (permissions, employee info, and projects) + static Future> 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 featurePermissions = decoded['data']['featurePermissions']; + final data = json.decode(response.body)['data']; - return featurePermissions - .map((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 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 _parsePermissions(List featurePermissions) { + return featurePermissions + .map((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 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 _parseProjectsInfo(List projectIds) { + return projectIds.map((id) => ProjectInfo.fromJson(id)).toList(); } } diff --git a/lib/model/projects_model.dart b/lib/model/projects_model.dart new file mode 100644 index 0000000..ff522a1 --- /dev/null +++ b/lib/model/projects_model.dart @@ -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; + } +} diff --git a/lib/view/dashboard/attendanceScreen.dart b/lib/view/dashboard/attendanceScreen.dart index 187c370..0e485f7 100644 --- a/lib/view/dashboard/attendanceScreen.dart +++ b/lib/view/dashboard/attendanceScreen.dart @@ -115,8 +115,26 @@ class _AttendanceScreenState extends State 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( + value: '', + child: MyText.bodySmall( + 'No Projects Assigned', + fontWeight: 600), + ) + ]; + } + + return accessibleProjects.map((project) { return PopupMenuItem( value: project.id.toString(), height: 32, @@ -138,7 +156,7 @@ class _AttendanceScreenState extends State with UIMixin { null ? attendanceController.projects .firstWhereOrNull((proj) => - proj.id== + proj.id == attendanceController .selectedProjectId) ?.name ?? @@ -861,7 +879,7 @@ class _AttendanceScreenState extends State with UIMixin { .captureAndUploadAttendance( log.id, log.employeeId, - attendanceController.selectedProjectId!, + attendanceController.selectedProjectId!, comment: "Rejected", action: 5, // Reject action imageCapture: false,