119 lines
3.4 KiB
Dart
119 lines
3.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:marco/helpers/services/api_service.dart';
|
|
import 'package:marco/model/employees/employee_model.dart';
|
|
import 'package:marco/helpers/services/app_logger.dart';
|
|
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
|
|
|
class AddServiceProjectJobController extends GetxController {
|
|
// Form Controllers
|
|
final titleCtrl = TextEditingController();
|
|
final descCtrl = TextEditingController();
|
|
final tagCtrl = TextEditingController();
|
|
final FocusNode searchFocusNode = FocusNode();
|
|
final RxBool showEmployeePicker = true.obs;
|
|
|
|
// Observables
|
|
final startDate = Rx<DateTime?>(DateTime.now());
|
|
final dueDate = Rx<DateTime?>(DateTime.now().add(const Duration(days: 1)));
|
|
final enteredTags = <String>[].obs;
|
|
|
|
final employees = <EmployeeModel>[].obs;
|
|
final selectedAssignees = <EmployeeModel>[].obs;
|
|
final isSearchingEmployees = false.obs;
|
|
|
|
// Loading states
|
|
final isLoading = false.obs;
|
|
final isAllEmployeeLoading = false.obs;
|
|
final allEmployees = <EmployeeModel>[].obs;
|
|
final employeeSearchResults = <EmployeeModel>[].obs;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
searchEmployees(""); // pass empty string safely
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
titleCtrl.dispose();
|
|
descCtrl.dispose();
|
|
tagCtrl.dispose();
|
|
super.onClose();
|
|
}
|
|
|
|
Future<void> searchEmployees(String query) async {
|
|
if (query.trim().isEmpty) {
|
|
employeeSearchResults.clear();
|
|
return;
|
|
}
|
|
isSearchingEmployees.value = true;
|
|
try {
|
|
final data =
|
|
await ApiService.searchEmployeesBasic(searchString: query.trim());
|
|
if (data is List) {
|
|
employeeSearchResults.assignAll(
|
|
data
|
|
.map((e) => EmployeeModel.fromJson(e as Map<String, dynamic>))
|
|
.toList(),
|
|
);
|
|
} else {
|
|
employeeSearchResults.clear();
|
|
}
|
|
} catch (e) {
|
|
logSafe("Error searching employees: $e", level: LogLevel.error);
|
|
employeeSearchResults.clear();
|
|
} finally {
|
|
isSearchingEmployees.value = false;
|
|
}
|
|
}
|
|
|
|
/// Toggle employee selection
|
|
void toggleAssignee(EmployeeModel employee) {
|
|
if (selectedAssignees.contains(employee)) {
|
|
selectedAssignees.remove(employee);
|
|
} else {
|
|
selectedAssignees.add(employee);
|
|
}
|
|
}
|
|
|
|
/// Create Service Project Job API call
|
|
Future<void> createJob(String projectId) async {
|
|
if (titleCtrl.text.trim().isEmpty || descCtrl.text.trim().isEmpty) {
|
|
showAppSnackbar(
|
|
title: "Validation",
|
|
message: "Title and Description are required",
|
|
type: SnackbarType.warning,
|
|
);
|
|
return;
|
|
}
|
|
|
|
final assigneeIds = selectedAssignees.map((e) => e.id).toList();
|
|
|
|
final success = await ApiService.createServiceProjectJobApi(
|
|
title: titleCtrl.text.trim(),
|
|
description: descCtrl.text.trim(),
|
|
projectId: projectId,
|
|
assignees: assigneeIds.map((id) => {"id": id}).toList(),
|
|
startDate: startDate.value!,
|
|
dueDate: dueDate.value!,
|
|
tags: enteredTags.map((tag) => {"name": tag}).toList(),
|
|
);
|
|
|
|
if (success) {
|
|
Get.back();
|
|
showAppSnackbar(
|
|
title: "Success",
|
|
message: "Job created successfully",
|
|
type: SnackbarType.success,
|
|
);
|
|
} else {
|
|
showAppSnackbar(
|
|
title: "Error",
|
|
message: "Failed to create job",
|
|
type: SnackbarType.error,
|
|
);
|
|
}
|
|
}
|
|
}
|