import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:marco/helpers/widgets/my_custom_skeleton.dart'; import 'package:marco/model/employees/employee_model.dart'; import 'package:marco/controller/task_Planning/daily_task_Planning_controller.dart'; class MultipleSelectRoleBottomSheet extends StatefulWidget { final String title; final bool multipleSelection; final String projectId; final String? serviceId; final String? organizationId; final String? roleId; final ScrollController? scrollController; final List initiallySelected; const MultipleSelectRoleBottomSheet({ super.key, this.title = "Select Employees", this.multipleSelection = true, required this.projectId, this.serviceId, this.organizationId, this.roleId, this.initiallySelected = const [], this.scrollController, }); @override State createState() => _MultipleSelectRoleBottomSheetState(); } class _MultipleSelectRoleBottomSheetState extends State { final RxList _employees = [].obs; final RxList _filtered = [].obs; final RxBool _isLoading = true.obs; late RxList _selected; final TextEditingController _searchController = TextEditingController(); late DailyTaskPlanningController controller; @override void initState() { super.initState(); _selected = widget.initiallySelected.obs; controller = Get.find(); _fetchEmployeesFiltered(); } Future _fetchEmployeesFiltered() async { _isLoading.value = true; try { List employees = controller.employees.toList(); if (widget.roleId != null && widget.roleId!.isNotEmpty) { employees = employees .where((emp) => emp.jobRoleID == widget.roleId) .toList(); } // Selected first employees.sort((a, b) { final aSel = _selected.any((e) => e.id == a.id) ? 0 : 1; final bSel = _selected.any((e) => e.id == b.id) ? 0 : 1; return aSel != bSel ? aSel.compareTo(bSel) : a.name.toLowerCase().compareTo(b.name.toLowerCase()); }); _employees.assignAll(employees); _filtered.assignAll(employees); } catch (e) { print("Error fetching employees: $e"); } finally { _isLoading.value = false; } } void _onSearch(String text) { if (text.isEmpty) { _filtered.assignAll(_employees); } else { _filtered.assignAll( _employees.where((e) => e.name.toLowerCase().contains(text.toLowerCase()) || e.designation.toLowerCase().contains(text.toLowerCase())), ); } // Selected on top _filtered.sort((a, b) { final aSel = _selected.any((e) => e.id == a.id) ? 0 : 1; final bSel = _selected.any((e) => e.id == b.id) ? 0 : 1; return aSel != bSel ? aSel.compareTo(bSel) : a.name.toLowerCase().compareTo(b.name.toLowerCase()); }); } void _onTap(EmployeeModel emp) { if (widget.multipleSelection) { if (_selected.any((e) => e.id == emp.id)) { _selected.removeWhere((e) => e.id == emp.id); } else { _selected.add(emp); } } else { _selected.assignAll([emp]); Get.back(result: _selected); } _onSearch(_searchController.text.trim()); } bool _isSelected(EmployeeModel emp) { return _selected.any((e) => e.id == emp.id); } Widget _searchBar() => Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: TextField( controller: _searchController, onChanged: _onSearch, decoration: InputDecoration( hintText: 'Search employees...', filled: true, fillColor: Colors.grey.shade100, prefixIcon: const Icon(Icons.search, color: Colors.grey), suffixIcon: _searchController.text.isNotEmpty ? IconButton( icon: const Icon(Icons.close, color: Colors.grey), onPressed: () { _searchController.clear(); _onSearch(''); }, ) : null, contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), border: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: BorderSide.none, ), ), ), ); /// ⭐ NEW — Chips showing selected employees Widget _selectedChips() { return Obx(() { if (_selected.isEmpty) return const SizedBox(); return Wrap( spacing: 8, runSpacing: 8, children: _selected.map((emp) { return Chip( label: Text(emp.name), deleteIcon: const Icon(Icons.close), onDeleted: () { _selected.remove(emp); _onSearch(_searchController.text.trim()); }, backgroundColor: Colors.blue.shade50, ); }).toList(), ); }); } @override Widget build(BuildContext context) { return BaseBottomSheet( title: widget.title, onCancel: () => Get.back(), onSubmit: () => Get.back(result: _selected), child: SizedBox( height: MediaQuery.of(context).size.height * 0.55, child: Column( children: [ _searchBar(), /// ⭐ Chips shown right below search bar Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: _selectedChips(), ), const SizedBox(height: 6), Expanded( child: Obx(() { if (_isLoading.value) { return SkeletonLoaders.employeeSkeletonCard(); } if (_filtered.isEmpty) { return const Center(child: Text("No employees found")); } return ListView.builder( controller: widget.scrollController, padding: const EdgeInsets.only(bottom: 20), itemCount: _filtered.length, itemBuilder: (_, index) { final emp = _filtered[index]; final isSelected = _isSelected(emp); return ListTile( onTap: () => _onTap(emp), leading: CircleAvatar( backgroundColor: Colors.blueAccent, child: Text( emp.name.isNotEmpty ? emp.name[0].toUpperCase() : "?", style: const TextStyle(color: Colors.white), ), ), title: Text(emp.name), subtitle: Text(emp.designation), trailing: Checkbox( value: isSelected, onChanged: (_) => _onTap(emp), ), contentPadding: const EdgeInsets.symmetric( horizontal: 4, vertical: 6, ), ); }, ); }), ), ], ), ), ); } }