317 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			317 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'package:get/get.dart';
 | |
| import 'package:marco/helpers/services/api_service.dart';
 | |
| import 'package:marco/helpers/services/app_logger.dart';
 | |
| import 'package:marco/helpers/widgets/my_snackbar.dart';
 | |
| 
 | |
| class AddContactController extends GetxController {
 | |
|   final RxList<String> categories = <String>[].obs;
 | |
|   final RxList<String> buckets = <String>[].obs;
 | |
|   final RxList<String> globalProjects = <String>[].obs;
 | |
|   final RxList<String> tags = <String>[].obs;
 | |
| 
 | |
|   final RxString selectedCategory = ''.obs;
 | |
|   final RxList<String> selectedBuckets = <String>[].obs;
 | |
|   final RxString selectedProject = ''.obs;
 | |
| 
 | |
|   final RxList<String> enteredTags = <String>[].obs;
 | |
|   final RxList<String> filteredSuggestions = <String>[].obs;
 | |
|   final RxList<String> organizationNames = <String>[].obs;
 | |
|   final RxList<String> filteredOrgSuggestions = <String>[].obs;
 | |
| 
 | |
|   final RxMap<String, String> categoriesMap = <String, String>{}.obs;
 | |
|   final RxMap<String, String> bucketsMap = <String, String>{}.obs;
 | |
|   final RxMap<String, String> projectsMap = <String, String>{}.obs;
 | |
|   final RxMap<String, String> tagsMap = <String, String>{}.obs;
 | |
|   final RxBool isInitialized = false.obs;
 | |
|   final RxList<String> selectedProjects = <String>[].obs;
 | |
|   final RxBool isSubmitting = false.obs;
 | |
| 
 | |
|   @override
 | |
|   void onInit() {
 | |
|     super.onInit();
 | |
|     logSafe("AddContactController initialized", level: LogLevel.debug);
 | |
|     fetchInitialData();
 | |
|   }
 | |
| 
 | |
|   Future<void> fetchInitialData() async {
 | |
|     logSafe("Fetching initial dropdown data", level: LogLevel.debug);
 | |
|     await Future.wait([
 | |
|       fetchBuckets(),
 | |
|       fetchGlobalProjects(),
 | |
|       fetchTags(),
 | |
|       fetchCategories(),
 | |
|       fetchOrganizationNames(),
 | |
|     ]);
 | |
| 
 | |
|     // ✅ Mark initialization as done
 | |
|     isInitialized.value = true;
 | |
|   }
 | |
| 
 | |
|   void resetForm() {
 | |
|     selectedCategory.value = '';
 | |
|     selectedProject.value = '';
 | |
|     selectedBuckets.clear();
 | |
|     enteredTags.clear();
 | |
|     filteredSuggestions.clear();
 | |
|     filteredOrgSuggestions.clear();
 | |
|     selectedProjects.clear();
 | |
|   }
 | |
| 
 | |
|   Future<void> fetchBuckets() async {
 | |
|     try {
 | |
|       final response = await ApiService.getContactBucketList();
 | |
|       if (response != null && response['data'] is List) {
 | |
|         final names = <String>[];
 | |
|         for (var item in response['data']) {
 | |
|           if (item['name'] != null && item['id'] != null) {
 | |
|             bucketsMap[item['name']] = item['id'].toString();
 | |
|             names.add(item['name']);
 | |
|           }
 | |
|         }
 | |
|         buckets.assignAll(names);
 | |
|         logSafe("Fetched \${names.length} buckets");
 | |
|       }
 | |
|     } catch (e) {
 | |
|       logSafe("Failed to fetch buckets: \$e", level: LogLevel.error);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Future<void> fetchOrganizationNames() async {
 | |
|     try {
 | |
|       final orgs = await ApiService.getOrganizationList();
 | |
|       organizationNames.assignAll(orgs);
 | |
|       logSafe("Fetched \${orgs.length} organization names");
 | |
|     } catch (e) {
 | |
|       logSafe("Failed to load organization names: \$e", level: LogLevel.error);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Future<void> submitContact({
 | |
|     String? id,
 | |
|     required String name,
 | |
|     required String organization,
 | |
|     required List<Map<String, String>> emails,
 | |
|     required List<Map<String, String>> phones,
 | |
|     required String address,
 | |
|     required String description,
 | |
|     String? designation,
 | |
|   }) async {
 | |
|     if (isSubmitting.value) return;
 | |
|     isSubmitting.value = true;
 | |
| 
 | |
|     final categoryId = categoriesMap[selectedCategory.value];
 | |
|     final bucketIds = selectedBuckets
 | |
|         .map((name) => bucketsMap[name])
 | |
|         .whereType<String>()
 | |
|         .toList();
 | |
| 
 | |
|     if (bucketIds.isEmpty) {
 | |
|       showAppSnackbar(
 | |
|         title: "Missing Buckets",
 | |
|         message: "Please select at least one bucket.",
 | |
|         type: SnackbarType.warning,
 | |
|       );
 | |
|       isSubmitting.value = false;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     final projectIds = selectedProjects
 | |
|         .map((name) => projectsMap[name])
 | |
|         .whereType<String>()
 | |
|         .toList();
 | |
| 
 | |
|     if (name.trim().isEmpty) {
 | |
|       showAppSnackbar(
 | |
|         title: "Missing Name",
 | |
|         message: "Please enter the contact name.",
 | |
|         type: SnackbarType.warning,
 | |
|       );
 | |
|       isSubmitting.value = false;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     if (organization.trim().isEmpty) {
 | |
|       showAppSnackbar(
 | |
|         title: "Missing Organization",
 | |
|         message: "Please enter the organization name.",
 | |
|         type: SnackbarType.warning,
 | |
|       );
 | |
|       isSubmitting.value = false;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     if (selectedBuckets.isEmpty) {
 | |
|       showAppSnackbar(
 | |
|         title: "Missing Bucket",
 | |
|         message: "Please select at least one bucket.",
 | |
|         type: SnackbarType.warning,
 | |
|       );
 | |
|       isSubmitting.value = false;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     try {
 | |
|       final tagObjects = enteredTags.map((tagName) {
 | |
|         final tagId = tagsMap[tagName];
 | |
|         return tagId != null
 | |
|             ? {"id": tagId, "name": tagName}
 | |
|             : {"name": tagName};
 | |
|       }).toList();
 | |
| 
 | |
|       final body = {
 | |
|         if (id != null) "id": id,
 | |
|         "name": name.trim(),
 | |
|         "organization": organization.trim(),
 | |
|         if (selectedCategory.value.isNotEmpty && categoryId != null)
 | |
|           "contactCategoryId": categoryId,
 | |
|         if (projectIds.isNotEmpty) "projectIds": projectIds,
 | |
|         "bucketIds": bucketIds,
 | |
|         if (enteredTags.isNotEmpty) "tags": tagObjects,
 | |
|         if (emails.isNotEmpty) "contactEmails": emails,
 | |
|         if (phones.isNotEmpty) "contactPhones": phones,
 | |
|         if (address.trim().isNotEmpty) "address": address.trim(),
 | |
|         if (description.trim().isNotEmpty) "description": description.trim(),
 | |
|         if (designation != null && designation.trim().isNotEmpty)
 | |
|           "designation": designation.trim(),
 | |
|       };
 | |
| 
 | |
|       logSafe("${id != null ? 'Updating' : 'Creating'} contact");
 | |
| 
 | |
|       final response = id != null
 | |
|           ? await ApiService.updateContact(id, body)
 | |
|           : await ApiService.createContact(body);
 | |
| 
 | |
|       if (response == true) {
 | |
|         Get.back(result: true);
 | |
|         showAppSnackbar(
 | |
|           title: "Success",
 | |
|           message: id != null
 | |
|               ? "Contact updated successfully"
 | |
|               : "Contact created successfully",
 | |
|           type: SnackbarType.success,
 | |
|         );
 | |
|       } else {
 | |
|         showAppSnackbar(
 | |
|           title: "Error",
 | |
|           message: "Failed to ${id != null ? 'update' : 'create'} contact",
 | |
|           type: SnackbarType.error,
 | |
|         );
 | |
|       }
 | |
|     } catch (e) {
 | |
|       logSafe("Submit contact error: $e", level: LogLevel.error);
 | |
|       showAppSnackbar(
 | |
|         title: "Error",
 | |
|         message: "Something went wrong",
 | |
|         type: SnackbarType.error,
 | |
|       );
 | |
|     } finally {
 | |
|       isSubmitting.value = false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void filterOrganizationSuggestions(String query) {
 | |
|     if (query.trim().isEmpty) {
 | |
|       filteredOrgSuggestions.clear();
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     final lower = query.toLowerCase();
 | |
|     filteredOrgSuggestions.assignAll(
 | |
|       organizationNames
 | |
|           .where((name) => name.toLowerCase().contains(lower))
 | |
|           .toList(),
 | |
|     );
 | |
|     logSafe("Filtered organization suggestions for: \$query",
 | |
|         level: LogLevel.debug);
 | |
|   }
 | |
| 
 | |
|   Future<void> fetchGlobalProjects() async {
 | |
|     try {
 | |
|       final response = await ApiService.getGlobalProjects();
 | |
|       if (response != null) {
 | |
|         final names = <String>[];
 | |
|         for (var item in response) {
 | |
|           final name = item['name']?.toString().trim();
 | |
|           final id = item['id']?.toString().trim();
 | |
|           if (name != null && id != null && name.isNotEmpty) {
 | |
|             projectsMap[name] = id;
 | |
|             names.add(name);
 | |
|           }
 | |
|         }
 | |
|         globalProjects.assignAll(names);
 | |
|         logSafe("Fetched \${names.length} global projects");
 | |
|       }
 | |
|     } catch (e) {
 | |
|       logSafe("Failed to fetch global projects: \$e", level: LogLevel.error);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Future<void> fetchTags() async {
 | |
|     try {
 | |
|       final response = await ApiService.getContactTagList();
 | |
|       if (response != null && response['data'] is List) {
 | |
|         tags.assignAll(List<String>.from(
 | |
|           response['data'].map((e) => e['name'] ?? '').where((e) => e != ''),
 | |
|         ));
 | |
|         logSafe("Fetched \${tags.length} tags");
 | |
|       }
 | |
|     } catch (e) {
 | |
|       logSafe("Failed to fetch tags: \$e", level: LogLevel.error);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void filterSuggestions(String query) {
 | |
|     if (query.trim().isEmpty) {
 | |
|       filteredSuggestions.clear();
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     final lower = query.toLowerCase();
 | |
|     filteredSuggestions.assignAll(
 | |
|       tags
 | |
|           .where((tag) =>
 | |
|               tag.toLowerCase().contains(lower) && !enteredTags.contains(tag))
 | |
|           .toList(),
 | |
|     );
 | |
|     logSafe("Filtered tag suggestions for: \$query", level: LogLevel.debug);
 | |
|   }
 | |
| 
 | |
|   void clearSuggestions() {
 | |
|     filteredSuggestions.clear();
 | |
|     logSafe("Cleared tag suggestions", level: LogLevel.debug);
 | |
|   }
 | |
| 
 | |
|   Future<void> fetchCategories() async {
 | |
|     try {
 | |
|       final response = await ApiService.getContactCategoryList();
 | |
|       if (response != null && response['data'] is List) {
 | |
|         final names = <String>[];
 | |
|         for (var item in response['data']) {
 | |
|           final name = item['name']?.toString().trim();
 | |
|           final id = item['id']?.toString().trim();
 | |
|           if (name != null && id != null && name.isNotEmpty) {
 | |
|             categoriesMap[name] = id;
 | |
|             names.add(name);
 | |
|           }
 | |
|         }
 | |
|         categories.assignAll(names);
 | |
|         logSafe("Fetched \${names.length} contact categories");
 | |
|       }
 | |
|     } catch (e) {
 | |
|       logSafe("Failed to fetch categories: \$e", level: LogLevel.error);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void addEnteredTag(String tag) {
 | |
|     if (tag.trim().isNotEmpty && !enteredTags.contains(tag.trim())) {
 | |
|       enteredTags.add(tag.trim());
 | |
|       logSafe("Added tag: \$tag", level: LogLevel.debug);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void removeEnteredTag(String tag) {
 | |
|     enteredTags.remove(tag);
 | |
|     logSafe("Removed tag: \$tag", level: LogLevel.debug);
 | |
|   }
 | |
| }
 |