marco.pms.mobileapp/lib/model/employees/multiple_select_bottomsheet.dart

160 lines
5.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:marco/helpers/utils/base_bottom_sheet.dart';
import 'package:marco/model/employees/employee_model.dart';
import 'package:marco/helpers/services/api_service.dart';
class EmployeeSelectionBottomSheet extends StatefulWidget {
final List<EmployeeModel> initiallySelected;
final bool multipleSelection;
final String title;
const EmployeeSelectionBottomSheet({
Key? key,
this.initiallySelected = const [],
this.multipleSelection = true,
this.title = 'Select Employees',
}) : super(key: key);
@override
State<EmployeeSelectionBottomSheet> createState() =>
_EmployeeSelectionBottomSheetState();
}
class _EmployeeSelectionBottomSheetState
extends State<EmployeeSelectionBottomSheet> {
final TextEditingController _searchController = TextEditingController();
final RxBool _isSearching = false.obs;
final RxList<EmployeeModel> _searchResults = <EmployeeModel>[].obs;
late RxList<EmployeeModel> _selectedEmployees;
@override
void initState() {
super.initState();
_selectedEmployees = RxList<EmployeeModel>.from(widget.initiallySelected);
_searchEmployees('');
}
@override
void dispose() {
_searchController.dispose();
super.dispose();
}
Future<void> _searchEmployees(String query) async {
_isSearching.value = true;
final data = await ApiService.searchEmployeesBasic(searchString: query);
final results = (data as List)
.map((e) => EmployeeModel.fromJson(e as Map<String, dynamic>))
.toList();
_searchResults.assignAll(results);
_isSearching.value = false;
}
void _toggleEmployee(EmployeeModel emp) {
if (widget.multipleSelection) {
if (_selectedEmployees.contains(emp)) {
_selectedEmployees.remove(emp);
} else {
_selectedEmployees.add(emp);
}
_selectedEmployees.refresh();
} else {
_selectedEmployees.assignAll([emp]);
_selectedEmployees.refresh();
}
}
void _handleSubmit() {
if (widget.multipleSelection) {
Navigator.of(context).pop(_selectedEmployees.toList());
} else {
Navigator.of(context)
.pop(_selectedEmployees.isNotEmpty ? _selectedEmployees.first : null);
}
}
Widget _searchBar() => Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: TextField(
controller: _searchController,
onChanged: _searchEmployees,
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();
_searchEmployees('');
},
)
: null,
contentPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide.none,
),
),
),
);
Widget _employeeList() => Expanded(
child: ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 4),
itemCount: _searchResults.length,
itemBuilder: (context, index) {
final emp = _searchResults[index];
return Obx(() {
// wrap each tile
final isSelected = _selectedEmployees.contains(emp);
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blueAccent,
child: Text(
(emp.firstName.isNotEmpty ? emp.firstName[0] : 'U')
.toUpperCase(),
style: const TextStyle(color: Colors.white),
),
),
title: Text('${emp.firstName} ${emp.lastName}'),
subtitle: Text(emp.email),
trailing: Checkbox(
value: isSelected,
onChanged: (_) => _toggleEmployee(emp),
fillColor: MaterialStateProperty.resolveWith<Color>(
(states) => states.contains(MaterialState.selected)
? Colors.blueAccent
: Colors.white,
),
),
onTap: () => _toggleEmployee(emp),
contentPadding:
const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
);
});
},
),
);
@override
Widget build(BuildContext context) {
return BaseBottomSheet(
title: widget.title,
onCancel: () => Navigator.of(context).pop(),
onSubmit: _handleSubmit,
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.7,
child: Column(children: [
_searchBar(),
_employeeList(),
]),
),
);
}
}