265 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			265 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'package:get/get.dart';
 | |
| import 'package:marco/helpers/services/app_logger.dart';
 | |
| import 'package:marco/helpers/services/api_service.dart';
 | |
| import 'package:marco/helpers/widgets/my_form_validator.dart';
 | |
| import 'package:marco/helpers/widgets/my_snackbar.dart';
 | |
| import 'package:marco/model/project_model.dart';
 | |
| import 'package:marco/model/dailyTaskPlanning/daily_task_planning_model.dart';
 | |
| import 'package:marco/model/employees/employee_model.dart';
 | |
| 
 | |
| class DailyTaskPlanningController extends GetxController {
 | |
|   List<ProjectModel> projects = [];
 | |
|   RxList<EmployeeModel> employees = <EmployeeModel>[].obs;
 | |
|   RxList<EmployeeModel> selectedEmployees = <EmployeeModel>[].obs;
 | |
|   List<EmployeeModel> allEmployeesCache = [];
 | |
|   List<TaskPlanningDetailsModel> dailyTasks = [];
 | |
|   RxMap<String, RxBool> uploadingStates = <String, RxBool>{}.obs;
 | |
| 
 | |
|   MyFormValidator basicValidator = MyFormValidator();
 | |
|   List<Map<String, dynamic>> roles = [];
 | |
|   RxBool isAssigningTask = false.obs;
 | |
|   RxnString selectedRoleId = RxnString();
 | |
|   RxBool isFetchingTasks = true.obs;
 | |
|   RxBool isFetchingProjects = true.obs;
 | |
|   RxBool isFetchingEmployees = true.obs;
 | |
| 
 | |
|   @override
 | |
|   void onInit() {
 | |
|     super.onInit();
 | |
|     fetchRoles();
 | |
|   }
 | |
| 
 | |
|   String? formFieldValidator(String? value, {required String fieldType}) {
 | |
|     if (value == null || value.trim().isEmpty) return 'This field is required';
 | |
|     if (fieldType == "target" && int.tryParse(value.trim()) == null) {
 | |
|       return 'Please enter a valid number';
 | |
|     }
 | |
|     if (fieldType == "description" && value.trim().length < 5) {
 | |
|       return 'Description must be at least 5 characters';
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   void updateSelectedEmployees() {
 | |
|     selectedEmployees.value =
 | |
|         employees.where((e) => uploadingStates[e.id]?.value == true).toList();
 | |
|     logSafe("Updated selected employees", level: LogLevel.debug);
 | |
|   }
 | |
| 
 | |
|   void onRoleSelected(String? roleId) {
 | |
|     selectedRoleId.value = roleId;
 | |
|     logSafe("Role selected", level: LogLevel.info);
 | |
|   }
 | |
| 
 | |
|   Future<void> fetchRoles() async {
 | |
|     logSafe("Fetching roles...", level: LogLevel.info);
 | |
|     final result = await ApiService.getRoles();
 | |
|     if (result != null) {
 | |
|       roles = List<Map<String, dynamic>>.from(result);
 | |
|       logSafe("Roles fetched successfully", level: LogLevel.info);
 | |
|       update();
 | |
|     } else {
 | |
|       logSafe("Failed to fetch roles", level: LogLevel.error);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Future<bool> assignDailyTask({
 | |
|     required String workItemId,
 | |
|     required int plannedTask,
 | |
|     required String description,
 | |
|     required List<String> taskTeam,
 | |
|     DateTime? assignmentDate,
 | |
|     String? organizationId,
 | |
|     String? serviceId,
 | |
|   }) async {
 | |
|     isAssigningTask.value = true;
 | |
|     logSafe("Starting assign task...", level: LogLevel.info);
 | |
| 
 | |
|     final response = await ApiService.assignDailyTask(
 | |
|       workItemId: workItemId,
 | |
|       plannedTask: plannedTask,
 | |
|       description: description,
 | |
|       taskTeam: taskTeam,
 | |
|       assignmentDate: assignmentDate,
 | |
|       organizationId: organizationId,
 | |
|       serviceId: serviceId,
 | |
|     );
 | |
| 
 | |
|     isAssigningTask.value = false;
 | |
| 
 | |
|     if (response == true) {
 | |
|       logSafe("Task assigned successfully", level: LogLevel.info);
 | |
|       showAppSnackbar(
 | |
|         title: "Success",
 | |
|         message: "Task assigned successfully!",
 | |
|         type: SnackbarType.success,
 | |
|       );
 | |
|       return true;
 | |
|     } else {
 | |
|       logSafe("Failed to assign task", level: LogLevel.error);
 | |
|       showAppSnackbar(
 | |
|         title: "Error",
 | |
|         message: "Failed to assign task.",
 | |
|         type: SnackbarType.error,
 | |
|       );
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /// Fetch Infra details and then tasks per work area
 | |
|   Future<void> fetchTaskData(String? projectId, {String? serviceId}) async {
 | |
|     if (projectId == null) return;
 | |
| 
 | |
|     isFetchingTasks.value = true;
 | |
|     try {
 | |
|       final infraResponse = await ApiService.getInfraDetails(
 | |
|         projectId,
 | |
|         serviceId: serviceId,
 | |
|       );
 | |
|       final infraData = infraResponse?['data'] as List<dynamic>?;
 | |
| 
 | |
|       if (infraData == null || infraData.isEmpty) {
 | |
|         dailyTasks = [];
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       dailyTasks = infraData.map((buildingJson) {
 | |
|         final building = Building(
 | |
|           id: buildingJson['id'],
 | |
|           name: buildingJson['buildingName'],
 | |
|           description: buildingJson['description'],
 | |
|           floors: (buildingJson['floors'] as List<dynamic>)
 | |
|               .map((floorJson) => Floor(
 | |
|                     id: floorJson['id'],
 | |
|                     floorName: floorJson['floorName'],
 | |
|                     workAreas: (floorJson['workAreas'] as List<dynamic>)
 | |
|                         .map((areaJson) => WorkArea(
 | |
|                               id: areaJson['id'],
 | |
|                               areaName: areaJson['areaName'],
 | |
|                               workItems: [],
 | |
|                             ))
 | |
|                         .toList(),
 | |
|                   ))
 | |
|               .toList(),
 | |
|         );
 | |
|         return TaskPlanningDetailsModel(
 | |
|           id: building.id,
 | |
|           name: building.name,
 | |
|           projectAddress: "",
 | |
|           contactPerson: "",
 | |
|           startDate: DateTime.now(),
 | |
|           endDate: DateTime.now(),
 | |
|           projectStatusId: "",
 | |
|           buildings: [building],
 | |
|         );
 | |
|       }).toList();
 | |
| 
 | |
|       await Future.wait(dailyTasks
 | |
|           .expand((task) => task.buildings)
 | |
|           .expand((b) => b.floors)
 | |
|           .expand((f) => f.workAreas)
 | |
|           .map((area) async {
 | |
|         try {
 | |
|           final taskResponse =
 | |
|               await ApiService.getWorkItemsByWorkArea(area.id, serviceId: serviceId);
 | |
|           final taskData = taskResponse?['data'] as List<dynamic>? ?? [];
 | |
|           area.workItems.addAll(taskData.map((taskJson) => WorkItemWrapper(
 | |
|                 workItemId: taskJson['id'],
 | |
|                 workItem: WorkItem(
 | |
|                   id: taskJson['id'],
 | |
|                   activityMaster: taskJson['activityMaster'] != null
 | |
|                       ? ActivityMaster.fromJson(taskJson['activityMaster'])
 | |
|                       : null,
 | |
|                   workCategoryMaster: taskJson['workCategoryMaster'] != null
 | |
|                       ? WorkCategoryMaster.fromJson(taskJson['workCategoryMaster'])
 | |
|                       : null,
 | |
|                   plannedWork: (taskJson['plannedWork'] as num?)?.toDouble(),
 | |
|                   completedWork: (taskJson['completedWork'] as num?)?.toDouble(),
 | |
|                   todaysAssigned: (taskJson['todaysAssigned'] as num?)?.toDouble(),
 | |
|                   description: taskJson['description'] as String?,
 | |
|                   taskDate: taskJson['taskDate'] != null
 | |
|                       ? DateTime.tryParse(taskJson['taskDate'])
 | |
|                       : null,
 | |
|                 ),
 | |
|               )));
 | |
|         } catch (e, stack) {
 | |
|           logSafe("Error fetching tasks for work area ${area.id}",
 | |
|               level: LogLevel.error, error: e, stackTrace: stack);
 | |
|         }
 | |
|       }));
 | |
|     } catch (e, stack) {
 | |
|       logSafe("Error fetching daily task data",
 | |
|           level: LogLevel.error, error: e, stackTrace: stack);
 | |
|     } finally {
 | |
|       isFetchingTasks.value = false;
 | |
|       update();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Future<void> fetchEmployeesByProjectService({
 | |
|     required String projectId,
 | |
|     String? serviceId,
 | |
|     String? organizationId,
 | |
|   }) async {
 | |
|     isFetchingEmployees.value = true;
 | |
| 
 | |
|     try {
 | |
|       final response = await ApiService.getEmployeesByProjectService(
 | |
|         projectId,
 | |
|         serviceId: serviceId ?? '',
 | |
|         organizationId: organizationId ?? '',
 | |
|       );
 | |
| 
 | |
|       if (response != null && response.isNotEmpty) {
 | |
|         employees.assignAll(response.map((json) => EmployeeModel.fromJson(json)));
 | |
| 
 | |
|         if (serviceId == null && organizationId == null) {
 | |
|           allEmployeesCache = List.from(employees);
 | |
|         }
 | |
| 
 | |
|         final currentEmployeeIds = employees.map((e) => e.id).toSet();
 | |
| 
 | |
|         uploadingStates.removeWhere((key, _) => !currentEmployeeIds.contains(key));
 | |
|         employees.forEach((emp) {
 | |
|           uploadingStates.putIfAbsent(emp.id, () => false.obs);
 | |
|         });
 | |
| 
 | |
|         selectedEmployees.removeWhere((e) => !currentEmployeeIds.contains(e.id));
 | |
| 
 | |
|         logSafe("Employees fetched: ${employees.length}", level: LogLevel.info);
 | |
|       } else {
 | |
|         employees.clear();
 | |
|         uploadingStates.clear();
 | |
|         selectedEmployees.clear();
 | |
|         logSafe(
 | |
|           serviceId != null || organizationId != null
 | |
|               ? "Filtered employees empty"
 | |
|               : "No employees found",
 | |
|           level: LogLevel.warning,
 | |
|         );
 | |
|       }
 | |
|     } catch (e, stack) {
 | |
|       logSafe("Error fetching employees", level: LogLevel.error, error: e, stackTrace: stack);
 | |
| 
 | |
|       if (serviceId == null && organizationId == null && allEmployeesCache.isNotEmpty) {
 | |
|         employees.assignAll(allEmployeesCache);
 | |
| 
 | |
|         final cachedEmployeeIds = employees.map((e) => e.id).toSet();
 | |
|         uploadingStates.removeWhere((key, _) => !cachedEmployeeIds.contains(key));
 | |
|         employees.forEach((emp) {
 | |
|           uploadingStates.putIfAbsent(emp.id, () => false.obs);
 | |
|         });
 | |
| 
 | |
|         selectedEmployees.removeWhere((e) => !cachedEmployeeIds.contains(e.id));
 | |
|       } else {
 | |
|         employees.clear();
 | |
|         uploadingStates.clear();
 | |
|         selectedEmployees.clear();
 | |
|       }
 | |
|     } finally {
 | |
|       isFetchingEmployees.value = false;
 | |
|       update();
 | |
|     }
 | |
|   }
 | |
| }
 |