diff --git a/lib/model/dailyTaskPlanning/assign_task_bottom_sheet .dart b/lib/model/dailyTaskPlanning/assign_task_bottom_sheet .dart index ce19774..ff9b33b 100644 --- a/lib/model/dailyTaskPlanning/assign_task_bottom_sheet .dart +++ b/lib/model/dailyTaskPlanning/assign_task_bottom_sheet .dart @@ -15,8 +15,10 @@ import 'package:marco/helpers/widgets/tenant/organization_selector.dart'; import 'package:marco/helpers/widgets/tenant/service_selector.dart'; import 'package:marco/model/attendance/organization_per_project_list_model.dart'; import 'package:marco/model/tenant/tenant_services_model.dart'; + +// Added imports for employee selection import 'package:marco/model/employees/employee_model.dart'; -import 'package:marco/model/employees/multiple_select_role_bottomsheet.dart'; +import 'package:marco/model/employees/multiple_select_bottomsheet.dart'; class AssignTaskBottomSheet extends StatefulWidget { final String workLocation; @@ -48,6 +50,8 @@ class _AssignTaskBottomSheetState extends State { final DailyTaskPlanningController controller = Get.find(); final ProjectController projectController = Get.find(); + final OrganizationController orgController = + Get.put(OrganizationController()); final OrganizationController orgController = Get.put(OrganizationController()); final ServiceController serviceController = Get.put(ServiceController()); @@ -85,10 +89,8 @@ class _AssignTaskBottomSheetState extends State { serviceId: selectedService?.id, organizationId: selectedOrganization?.id, ); - await controller.fetchTaskData( - selectedProjectId, - serviceId: selectedService?.id, - ); + await controller.fetchTaskData(selectedProjectId, + serviceId: selectedService?.id); } @override @@ -145,10 +147,13 @@ class _AssignTaskBottomSheetState extends State { _infoRow(Icons.location_on, "Work Location", "${widget.buildingName} > ${widget.floorName} > ${widget.workAreaName} > ${widget.activityName}"), const Divider(), + + // Pending Task Info _infoRow( Icons.pending_actions, "Pending Task", "${widget.pendingTask}"), const Divider(), + // Role Selector (kept as-is) GestureDetector( onTap: _onRoleMenuPressed, child: Row(children: [ @@ -160,52 +165,52 @@ class _AssignTaskBottomSheetState extends State { MySpacing.height(8), - /// TEAM SELECT BOX + // ------------------------------- + // Employee selector (REPLACED) + // ------------------------------- + // We show a button-like container (with border) that opens the reusable + // EmployeeSelectionBottomSheet. Selected employees are reflected using + // existing controller.uploadingStates & controller.selectedEmployees. GestureDetector( onTap: _openEmployeeSelectionSheet, child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.shade300), - borderRadius: BorderRadius.circular(6), - ), - child: Row( - children: [ - const Icon(Icons.group, color: Colors.black54), - const SizedBox(width: 10), - - // Expanded name area - Expanded( - child: Obx(() { - final count = controller.selectedEmployees.length; - if (count == 0) { - return MyText( - "Select team members", - color: Colors.grey.shade700, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ); - } - - final names = controller.selectedEmployees - .map((e) => e.name) - .join(", "); - - return Text( - names, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 14), - ); - }), - ), - - const Icon(Icons.arrow_drop_down, color: Colors.grey), - ], - )), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(6), + ), + child: Row( + children: [ + const Icon(Icons.group, color: Colors.black54), + const SizedBox(width: 10), + Expanded( + child: Obx(() { + final count = controller.selectedEmployees.length; + if (count == 0) { + return MyText("Select team members", + color: Colors.grey.shade700); + } + // show summary text when there are selected employees + final names = controller.selectedEmployees + .map((e) => e.name) + .join(", "); + return Text( + names, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 14), + ); + }), + ), + const SizedBox(width: 8), + const Icon(Icons.arrow_drop_down, color: Colors.grey), + ], + ), + ), ), - MySpacing.height(8), + + // Selected Employees Chips (keeps existing behavior) _buildSelectedEmployees(), MySpacing.height(8), @@ -233,6 +238,8 @@ class _AssignTaskBottomSheetState extends State { } void _onRoleMenuPressed() { + final RenderBox overlay = + Overlay.of(context).context.findRenderObject() as RenderBox; final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox; final Size screenSize = overlay.size; @@ -255,13 +262,13 @@ class _AssignTaskBottomSheetState extends State { ), ], ).then((value) { - if (value != null) { - selectedRoleId = value == 'all' ? null : value; - controller.onRoleSelected(selectedRoleId); - } + if (value != null) + controller.onRoleSelected(value == 'all' ? null : value); }); } + // Removed old inline employee list; selection handled by bottom sheet. + Widget _buildSelectedEmployees() { return Obx(() { if (controller.selectedEmployees.isEmpty) return Container(); @@ -307,15 +314,16 @@ class _AssignTaskBottomSheetState extends State { maxLines: maxLines, decoration: InputDecoration( hintText: hintText, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - ), + border: OutlineInputBorder(borderRadius: BorderRadius.circular(6)), contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), ), validator: (value) => this .controller .formFieldValidator(value, fieldType: validatorType), + validator: (value) => this + .controller + .formFieldValidator(value, fieldType: validatorType), ), ], ); @@ -334,16 +342,11 @@ class _AssignTaskBottomSheetState extends State { text: TextSpan( children: [ WidgetSpan( - child: MyText.titleMedium( - "$title: ", - fontWeight: 600, - color: Colors.black, - ), + child: MyText.titleMedium("$title: ", + fontWeight: 600, color: Colors.black), ), TextSpan( - text: value, - style: const TextStyle(color: Colors.black), - ), + text: value, style: const TextStyle(color: Colors.black)), ], ), ), @@ -354,41 +357,46 @@ class _AssignTaskBottomSheetState extends State { } Future _openEmployeeSelectionSheet() async { + // Open the existing EmployeeSelectionBottomSheet final result = await showModalBottomSheet>( context: context, isScrollControlled: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), - builder: (context) { - return DraggableScrollableSheet( - expand: false, - initialChildSize: 0.85, - minChildSize: 0.6, - maxChildSize: 1.0, - builder: (_, scrollController) { - return Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.vertical(top: Radius.circular(20)), - ), - child: MultipleSelectRoleBottomSheet( - projectId: selectedProjectId!, - organizationId: selectedOrganization?.id, - serviceId: selectedService?.id, - roleId: selectedRoleId, - initiallySelected: controller.selectedEmployees.toList(), - scrollController: scrollController, - ), - ); - }, - ); - }, + builder: (context) => EmployeeSelectionBottomSheet( + initiallySelected: controller.selectedEmployees.toList(), + multipleSelection: true, + title: 'Select Team Members', + ), ); - if (result != null) { - controller.selectedEmployees - .assignAll(result); // RxList updates UI automatically + if (result == null) return; + + // Merge returned employees into controller.uploadingStates & controller.selectedEmployees + // 1) Reset all uploadingStates to false, then set true for selected + controller.uploadingStates.forEach((key, rx) { + rx.value = false; + }); + + for (final emp in result) { + final idStr = emp.id.toString(); + if (controller.uploadingStates.containsKey(idStr)) { + controller.uploadingStates[idStr]?.value = true; + } else { + // if uploadingStates doesn't have the id yet, add it (safe fallback) + controller.uploadingStates[idStr] = RxBool(true); + } + } + + // 2) Update selectedEmployees list in controller + controller.selectedEmployees.assignAll(result); + + // 3) Call controller helper (keeps existing behavior) + try { + controller.updateSelectedEmployees(); + } catch (_) { + // If controller does not implement updateSelectedEmployees, ignore. } } @@ -397,20 +405,18 @@ class _AssignTaskBottomSheetState extends State { if (selectedTeam.isEmpty) { showAppSnackbar( - title: "Team Required", - message: "Please select at least one team member", - type: SnackbarType.error, - ); + title: "Team Required", + message: "Please select at least one team member", + type: SnackbarType.error); return; } final target = double.tryParse(targetController.text.trim()); if (target == null || target <= 0) { showAppSnackbar( - title: "Invalid Input", - message: "Please enter a valid target number", - type: SnackbarType.error, - ); + title: "Invalid Input", + message: "Please enter a valid target number", + type: SnackbarType.error); return; } @@ -426,10 +432,9 @@ class _AssignTaskBottomSheetState extends State { final description = descriptionController.text.trim(); if (description.isEmpty) { showAppSnackbar( - title: "Description Required", - message: "Please enter a description", - type: SnackbarType.error, - ); + title: "Description Required", + message: "Please enter a description", + type: SnackbarType.error); return; }