From 7e75431feb1dde8271405f4ba66986752e13ca55 Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Wed, 8 Oct 2025 11:20:50 +0530 Subject: [PATCH] fixed permissions loading issue on employee screen --- lib/controller/permission_controller.dart | 28 ++-- lib/view/employees/employees_screen.dart | 166 ++++++++++++---------- 2 files changed, 111 insertions(+), 83 deletions(-) diff --git a/lib/controller/permission_controller.dart b/lib/controller/permission_controller.dart index e78a0ba..815c455 100644 --- a/lib/controller/permission_controller.dart +++ b/lib/controller/permission_controller.dart @@ -13,6 +13,7 @@ class PermissionController extends GetxController { var employeeInfo = Rxn(); var projectsInfo = [].obs; Timer? _refreshTimer; + var isLoading = true.obs; @override void onInit() { @@ -26,7 +27,8 @@ class PermissionController extends GetxController { await loadData(token!); _startAutoRefresh(); } else { - logSafe("Token is null or empty. Skipping API load and auto-refresh.", level: LogLevel.warning); + logSafe("Token is null or empty. Skipping API load and auto-refresh.", + level: LogLevel.warning); } } @@ -37,19 +39,24 @@ class PermissionController extends GetxController { logSafe("Auth token retrieved: $token", level: LogLevel.debug); return token; } catch (e, stacktrace) { - logSafe("Error retrieving auth token", level: LogLevel.error, error: e, stackTrace: stacktrace); + logSafe("Error retrieving auth token", + level: LogLevel.error, error: e, stackTrace: stacktrace); return null; } } Future loadData(String token) async { try { + isLoading.value = true; final userData = await PermissionService.fetchAllUserData(token); _updateState(userData); await _storeData(); logSafe("Data loaded and state updated successfully."); } catch (e, stacktrace) { - logSafe("Error loading data from API", level: LogLevel.error, error: e, stackTrace: stacktrace); + logSafe("Error loading data from API", + level: LogLevel.error, error: e, stackTrace: stacktrace); + } finally { + isLoading.value = false; } } @@ -60,7 +67,8 @@ class PermissionController extends GetxController { projectsInfo.assignAll(userData['projects']); logSafe("State updated with user data."); } catch (e, stacktrace) { - logSafe("Error updating state", level: LogLevel.error, error: e, stackTrace: stacktrace); + logSafe("Error updating state", + level: LogLevel.error, error: e, stackTrace: stacktrace); } } @@ -89,7 +97,8 @@ class PermissionController extends GetxController { logSafe("User data successfully stored in SharedPreferences."); } catch (e, stacktrace) { - logSafe("Error storing data", level: LogLevel.error, error: e, stackTrace: stacktrace); + logSafe("Error storing data", + level: LogLevel.error, error: e, stackTrace: stacktrace); } } @@ -100,20 +109,23 @@ class PermissionController extends GetxController { if (token?.isNotEmpty ?? false) { await loadData(token!); } else { - logSafe("Token missing during auto-refresh. Skipping.", level: LogLevel.warning); + logSafe("Token missing during auto-refresh. Skipping.", + level: LogLevel.warning); } }); } bool hasPermission(String permissionId) { final hasPerm = permissions.any((p) => p.id == permissionId); - logSafe("Checking permission $permissionId: $hasPerm", level: LogLevel.debug); + logSafe("Checking permission $permissionId: $hasPerm", + level: LogLevel.debug); return hasPerm; } bool isUserAssignedToProject(String projectId) { final assigned = projectsInfo.any((project) => project.id == projectId); - logSafe("Checking project assignment for $projectId: $assigned", level: LogLevel.debug); + logSafe("Checking project assignment for $projectId: $assigned", + level: LogLevel.debug); return assigned; } diff --git a/lib/view/employees/employees_screen.dart b/lib/view/employees/employees_screen.dart index 79146de..d96d53f 100644 --- a/lib/view/employees/employees_screen.dart +++ b/lib/view/employees/employees_screen.dart @@ -248,33 +248,46 @@ class _EmployeesScreenState extends State with UIMixin { } Widget _buildFloatingActionButton() { - if (!permissionController.hasPermission(Permissions.manageEmployees)) { - return const SizedBox.shrink(); - } + return Obx(() { + // Show nothing while permissions are loading + if (permissionController.isLoading.value) { + return const SizedBox.shrink(); + } - return InkWell( - onTap: _onAddNewEmployee, - borderRadius: BorderRadius.circular(28), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - decoration: BoxDecoration( - color: Colors.red, - borderRadius: BorderRadius.circular(28), - boxShadow: const [ - BoxShadow( - color: Colors.black26, blurRadius: 6, offset: Offset(0, 3)) - ], + // Show FAB only if user has Manage Employees permission + final hasPermission = + permissionController.hasPermission(Permissions.manageEmployees); + if (!hasPermission) { + return const SizedBox.shrink(); + } + + return InkWell( + onTap: _onAddNewEmployee, + borderRadius: BorderRadius.circular(28), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(28), + boxShadow: const [ + BoxShadow( + color: Colors.black26, + blurRadius: 6, + offset: Offset(0, 3), + ) + ], + ), + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.add, color: Colors.white), + SizedBox(width: 8), + Text('Add New Employee', style: TextStyle(color: Colors.white)), + ], + ), ), - child: const Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(Icons.add, color: Colors.white), - SizedBox(width: 8), - Text('Add New Employee', style: TextStyle(color: Colors.white)), - ], - ), - ), - ); + ); + }); } Widget _buildSearchAndActionRow() { @@ -371,60 +384,63 @@ class _EmployeesScreenState extends State with UIMixin { } Widget _buildPopupMenu() { - if (!permissionController.hasPermission(Permissions.viewAllEmployees)) { - return const SizedBox.shrink(); - } + return Obx(() { + if (permissionController.isLoading.value || + !permissionController.hasPermission(Permissions.viewAllEmployees)) { + return const SizedBox.shrink(); + } - return PopupMenuButton( - icon: Stack( - clipBehavior: Clip.none, - children: [ - const Icon(Icons.tune, color: Colors.black), - Obx(() => _employeeController.isAllEmployeeSelected.value - ? Positioned( - right: -1, - top: -1, - child: Container( - width: 10, - height: 10, - decoration: const BoxDecoration( - color: Colors.red, shape: BoxShape.circle), + return PopupMenuButton( + icon: Stack( + clipBehavior: Clip.none, + children: [ + const Icon(Icons.tune, color: Colors.black), + Obx(() => _employeeController.isAllEmployeeSelected.value + ? Positioned( + right: -1, + top: -1, + child: Container( + width: 10, + height: 10, + decoration: const BoxDecoration( + color: Colors.red, shape: BoxShape.circle), + ), + ) + : const SizedBox.shrink()), + ], + ), + onSelected: (value) async { + if (value == 'all_employees') { + _employeeController.isAllEmployeeSelected.toggle(); + await _initEmployees(); + _employeeController.update(['employee_screen_controller']); + } + }, + itemBuilder: (_) => [ + PopupMenuItem( + value: 'all_employees', + child: Obx( + () => Row( + children: [ + Checkbox( + value: _employeeController.isAllEmployeeSelected.value, + onChanged: (_) => Navigator.pop(context, 'all_employees'), + checkColor: Colors.white, + activeColor: Colors.blueAccent, + side: const BorderSide(color: Colors.black, width: 1.5), + fillColor: MaterialStateProperty.resolveWith( + (states) => states.contains(MaterialState.selected) + ? Colors.blueAccent + : Colors.white), ), - ) - : const SizedBox.shrink()), - ], - ), - onSelected: (value) async { - if (value == 'all_employees') { - _employeeController.isAllEmployeeSelected.toggle(); - await _initEmployees(); - _employeeController.update(['employee_screen_controller']); - } - }, - itemBuilder: (_) => [ - PopupMenuItem( - value: 'all_employees', - child: Obx( - () => Row( - children: [ - Checkbox( - value: _employeeController.isAllEmployeeSelected.value, - onChanged: (_) => Navigator.pop(context, 'all_employees'), - checkColor: Colors.white, - activeColor: Colors.blueAccent, - side: const BorderSide(color: Colors.black, width: 1.5), - fillColor: MaterialStateProperty.resolveWith( - (states) => states.contains(MaterialState.selected) - ? Colors.blueAccent - : Colors.white), - ), - const Text('All Employees'), - ], + const Text('All Employees'), + ], + ), ), ), - ), - ], - ); + ], + ); + }); } Widget _buildEmployeeList() {