From 81692a1930561afb1a37d694d745ba251ada4bc6 Mon Sep 17 00:00:00 2001 From: Manish Date: Wed, 12 Nov 2025 12:04:35 +0530 Subject: [PATCH] implementation of Manage reporting --- lib/helpers/services/api_endpoints.dart | 2 - .../employees/employee_detail_screen.dart | 2 + .../manage_reporting_bottom_sheet.dart | 132 ++++-------------- 3 files changed, 30 insertions(+), 106 deletions(-) diff --git a/lib/helpers/services/api_endpoints.dart b/lib/helpers/services/api_endpoints.dart index 100c1dd..8f9f846 100644 --- a/lib/helpers/services/api_endpoints.dart +++ b/lib/helpers/services/api_endpoints.dart @@ -2,8 +2,6 @@ class ApiEndpoints { // static const String baseUrl = "https://stageapi.marcoaiot.com/api"; // static const String baseUrl = "https://api.marcoaiot.com/api"; // static const String baseUrl = "https://devapi.marcoaiot.com/api"; - static const String baseUrl = "https://mapi.marcoaiot.com/api"; - static const String getMasterCurrencies = "/Master/currencies/list"; static const String getMasterExpensesCategories = diff --git a/lib/view/employees/employee_detail_screen.dart b/lib/view/employees/employee_detail_screen.dart index baa59fa..6492674 100644 --- a/lib/view/employees/employee_detail_screen.dart +++ b/lib/view/employees/employee_detail_screen.dart @@ -13,6 +13,8 @@ import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:marco/helpers/widgets/my_custom_skeleton.dart'; import 'package:marco/view/employees/manage_reporting_bottom_sheet.dart'; import 'package:marco/model/employees/employee_model.dart'; +import 'package:marco/view/employees/manage_reporting_bottom_sheet.dart'; +import 'package:marco/model/employees/employee_model.dart'; import 'package:marco/view/employees/assign_employee_bottom_sheet.dart'; class EmployeeDetailPage extends StatefulWidget { diff --git a/lib/view/employees/manage_reporting_bottom_sheet.dart b/lib/view/employees/manage_reporting_bottom_sheet.dart index ba035c6..3eb5dd4 100644 --- a/lib/view/employees/manage_reporting_bottom_sheet.dart +++ b/lib/view/employees/manage_reporting_bottom_sheet.dart @@ -13,16 +13,14 @@ class ManageReportingBottomSheet extends StatefulWidget { final EmployeeModel? initialEmployee; final bool hideMainSelector; final bool renderAsCard; - final bool hideLoggedUserFromSelection; - final String? loggedUserId; + final bool hideLoggedUserFromSelection; // ✅ new const ManageReportingBottomSheet({ super.key, this.initialEmployee, this.hideMainSelector = false, this.renderAsCard = false, - this.hideLoggedUserFromSelection = false, - this.loggedUserId, + this.hideLoggedUserFromSelection = false, // default false }); @override @@ -213,76 +211,21 @@ class _ManageReportingBottomSheetState Future _handleSubmit() async { if (_selectedEmployee == null) { showAppSnackbar( - title: 'Error', - message: 'Please select the employee.', - type: SnackbarType.error, - ); + title: 'Error', + message: 'Please select the employee.', + type: SnackbarType.error); return; } - if (_selectedPrimary.isEmpty) { showAppSnackbar( - title: 'Error', - message: 'Please select at least one primary employee.', - type: SnackbarType.error, - ); + title: 'Error', + message: 'Please select at least one primary employee.', + type: SnackbarType.error); return; } - final employeeId = _selectedEmployee!.id; - - // === BUILD PAYLOAD (updated logic) === - - // fetch current assignments so we can deactivate old ones - List? currentAssignments; - try { - currentAssignments = - await ApiService.getOrganizationHierarchyList(employeeId); - } catch (_) { - currentAssignments = null; - } - - // helper sets of newly selected ids - final newPrimaryIds = _selectedPrimary.map((e) => e.id).toSet(); - final newSecondaryIds = _selectedSecondary.map((e) => e.id).toSet(); - final List> payload = []; - // 1) For current active assignments: if they are not in new selections -> add isActive:false - if (currentAssignments != null && currentAssignments.isNotEmpty) { - for (final item in currentAssignments) { - try { - final reportTo = item['reportTo']; - if (reportTo == null) continue; - final reportToId = reportTo['id'] as String?; - if (reportToId == null) continue; - final isPrimary = item['isPrimary'] == true; - final currentlyActive = - item['isActive'] == true || item['isActive'] == null; // be safe - - // if currently active and not included in new selection -> mark false - if (currentlyActive) { - if (isPrimary && !newPrimaryIds.contains(reportToId)) { - payload.add({ - "reportToId": reportToId, - "isPrimary": true, - "isActive": false, - }); - } else if (!isPrimary && !newSecondaryIds.contains(reportToId)) { - payload.add({ - "reportToId": reportToId, - "isPrimary": false, - "isActive": false, - }); - } - } - } catch (_) { - // ignore malformed items (same behavior as before) - } - } - } - - // 2) Add new primary (active) for (final emp in _selectedPrimary) { payload.add({ "reportToId": emp.id, @@ -290,8 +233,6 @@ class _ManageReportingBottomSheetState "isActive": true, }); } - - // 3) Add new secondary (active) for (final emp in _selectedSecondary) { payload.add({ "reportToId": emp.id, @@ -301,13 +242,11 @@ class _ManageReportingBottomSheetState } setState(() => _isSubmitting = true); - // show loader - Get.dialog( - const Center(child: CircularProgressIndicator()), - barrierDismissible: false, - ); + Get.dialog(const Center(child: CircularProgressIndicator()), + barrierDismissible: false); + final employeeId = _selectedEmployee!.id; final success = await ApiService.manageOrganizationHierarchy( employeeId: employeeId, payload: payload, @@ -315,36 +254,25 @@ class _ManageReportingBottomSheetState // hide loader if (Get.isDialogOpen == true) Get.back(); + setState(() => _isSubmitting = false); if (success) { showAppSnackbar( - title: 'Success', - message: 'Reporting assigned successfully', - type: SnackbarType.success, - ); + title: 'Success', + message: 'Reporting assigned successfully', + type: SnackbarType.success); - // ✅ Refresh both the organization hierarchy and employee details so UI shows updated managers - try { - final empId = employeeId; - final EmployeesScreenController controller = Get.find(); - await controller.fetchReportingManagers(empId); - await controller.fetchEmployeeDetails(empId); - } catch (_) { - // ignore if controller not found — not critical - } - - // Optional: re-fetch the organization hierarchy list (if needed elsewhere) + // Optionally refresh the saved hierarchy (not necessary here) but we can call: await ApiService.getOrganizationHierarchyList(employeeId); - // Keep sheet open and reset selections + // Keep sheet open and reset reporter selections for next assignment _resetForm(); } else { showAppSnackbar( - title: 'Error', - message: 'Failed to assign reporting. Please try again.', - type: SnackbarType.error, - ); + title: 'Error', + message: 'Failed to assign reporting. Please try again.', + type: SnackbarType.error); } } @@ -426,6 +354,11 @@ class _ManageReportingBottomSheetState backgroundColor: Colors.indigo.shade50, labelStyle: TextStyle(color: AppTheme.primaryColor), deleteIcon: const Icon(Icons.close, size: 16), + onDeleted: () => setState(() { + _selectedEmployee = null; + _selectEmployeeController.clear(); + _resetReportersOnly(); + }), ), ) else @@ -527,21 +460,12 @@ class _ManageReportingBottomSheetState spacing: 6, runSpacing: 6, children: selectedList.map((emp) { - final isProfileEmployee = widget.initialEmployee != null && - emp.id == widget.initialEmployee!.id; - return Chip( label: Text(emp.name, style: const TextStyle(fontSize: 12)), - backgroundColor: isProfileEmployee - ? Colors.indigo.shade50 - : Colors.indigo.shade50, + backgroundColor: Colors.indigo.shade50, labelStyle: TextStyle(color: AppTheme.primaryColor), - // Only show delete icon / action for non-profile employees - deleteIcon: isProfileEmployee - ? null - : const Icon(Icons.close, size: 16), - onDeleted: - isProfileEmployee ? null : () => selectedList.remove(emp), + deleteIcon: const Icon(Icons.close, size: 16), + onDeleted: () => selectedList.remove(emp), ); }).toList(), );