implementation of Manage reporting

This commit is contained in:
Manish 2025-11-12 12:04:35 +05:30 committed by Vaibhav Surve
parent 58c6a3f9af
commit b8aefc544f
2 changed files with 28 additions and 109 deletions

View File

@ -13,8 +13,6 @@ 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 {

View File

@ -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<void> _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<dynamic>? 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<Map<String, dynamic>> 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,39 +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 (_) {
}
// 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 reporter selections for next assignment
_resetForm();
if (Navigator.of(context).canPop()) {
Navigator.of(context).pop();
}
} 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);
}
}
@ -429,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
@ -530,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(),
);