import 'package:get/get.dart'; import 'package:logger/logger.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/model/attendance_model.dart'; import 'package:marco/model/project_model.dart'; import 'package:marco/model/employee_model.dart'; import 'package:marco/model/employees/employee_details_model.dart'; import 'package:marco/controller/project_controller.dart'; final Logger log = Logger(); class EmployeesScreenController extends GetxController { List attendances = []; List projects = []; String? selectedProjectId; List employeeDetails = []; RxBool isAllEmployeeSelected = false.obs; RxList employees = [].obs; RxBool isLoading = false.obs; RxMap uploadingStates = {}.obs; Rxn selectedEmployeeDetails = Rxn(); RxBool isLoadingEmployeeDetails = false.obs; @override void onInit() { super.onInit(); fetchAllProjects(); final projectId = Get.find().selectedProject?.id; if (projectId != null) { selectedProjectId = projectId; fetchEmployeesByProject(projectId); } else if (isAllEmployeeSelected.value) { fetchAllEmployees(); } else { clearEmployees(); } } Future fetchAllProjects() async { isLoading.value = true; await _handleApiCall( ApiService.getProjects, onSuccess: (data) { projects = data.map((json) => ProjectModel.fromJson(json)).toList(); log.i("Projects fetched: ${projects.length} projects loaded."); }, onEmpty: () => log.w("No project data found or API call failed."), ); isLoading.value = false; update(); } void clearEmployees() { employees.clear(); // Correct way to clear RxList log.i("Employees cleared"); update(['employee_screen_controller']); } Future fetchAllEmployees() async { isLoading.value = true; await _handleApiCall( ApiService.getAllEmployees, onSuccess: (data) { employees.assignAll(data.map((json) => EmployeeModel.fromJson(json))); log.i("All Employees fetched: ${employees.length} employees loaded."); }, onEmpty: () { employees.clear(); // Always clear on empty log.w("No Employee data found or API call failed."); }, ); isLoading.value = false; update(['employee_screen_controller']); } Future fetchEmployeesByProject(String? projectId) async { if (projectId == null || projectId.isEmpty) { log.e("Project ID is required but was null or empty."); return; } isLoading.value = true; await _handleApiCall( () => ApiService.getAllEmployeesByProject(projectId), onSuccess: (data) { employees.assignAll(data.map((json) => EmployeeModel.fromJson(json))); for (var emp in employees) { uploadingStates[emp.id] = false.obs; } log.i("Employees fetched: ${employees.length} for project $projectId"); }, onEmpty: () { employees.clear(); log.w("No employees found for project $projectId."); }, onError: (e) => log.e("Error fetching employees for project $projectId: $e"), ); isLoading.value = false; update(['employee_screen_controller']); } Future _handleApiCall( Future?> Function() apiCall, { required Function(List) onSuccess, required Function() onEmpty, Function(dynamic error)? onError, }) async { try { final response = await apiCall(); if (response != null && response.isNotEmpty) { onSuccess(response); } else { onEmpty(); } } catch (e) { if (onError != null) { onError(e); } else { log.e("API call error: $e"); } } } Future fetchEmployeeDetails(String? employeeId) async { if (employeeId == null || employeeId.isEmpty) return; isLoadingEmployeeDetails.value = true; await _handleSingleApiCall( () => ApiService.getEmployeeDetails(employeeId), onSuccess: (data) { selectedEmployeeDetails.value = EmployeeDetailsModel.fromJson(data); }, onEmpty: () { selectedEmployeeDetails.value = null; }, onError: (e) { selectedEmployeeDetails.value = null; }, ); isLoadingEmployeeDetails.value = false; } Future _handleSingleApiCall( Future?> Function() apiCall, { required Function(Map) onSuccess, required Function() onEmpty, Function(dynamic error)? onError, }) async { try { final response = await apiCall(); if (response != null && response.isNotEmpty) { onSuccess(response); } else { onEmpty(); } } catch (e) { if (onError != null) { onError(e); } else { log.e("API call error: $e"); } } } }