feat: enhance employee selection and validation in service project job form
This commit is contained in:
parent
0e575c393d
commit
49326e9929
@ -58,11 +58,10 @@ class _EmployeeSelectionBottomSheetState
|
||||
} else {
|
||||
_selectedEmployees.add(emp);
|
||||
}
|
||||
_selectedEmployees.refresh();
|
||||
} else {
|
||||
_selectedEmployees.assignAll([emp]);
|
||||
_selectedEmployees.refresh();
|
||||
}
|
||||
_selectedEmployees.refresh(); // important for Obx rebuild
|
||||
}
|
||||
|
||||
void _handleSubmit() {
|
||||
@ -104,13 +103,22 @@ class _EmployeeSelectionBottomSheetState
|
||||
);
|
||||
|
||||
Widget _employeeList() => Expanded(
|
||||
child: ListView.builder(
|
||||
child: Obx(() {
|
||||
if (_isSearching.value) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (_searchResults.isEmpty) {
|
||||
return const Center(child: Text("No employees found"));
|
||||
}
|
||||
|
||||
return 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(
|
||||
@ -125,20 +133,27 @@ class _EmployeeSelectionBottomSheetState
|
||||
subtitle: Text(emp.email),
|
||||
trailing: Checkbox(
|
||||
value: isSelected,
|
||||
onChanged: (_) => _toggleEmployee(emp),
|
||||
onChanged: (_) {
|
||||
FocusScope.of(context).unfocus(); // hide keyboard
|
||||
_toggleEmployee(emp);
|
||||
},
|
||||
fillColor: MaterialStateProperty.resolveWith<Color>(
|
||||
(states) => states.contains(MaterialState.selected)
|
||||
? Colors.blueAccent
|
||||
: Colors.white,
|
||||
),
|
||||
),
|
||||
onTap: () => _toggleEmployee(emp),
|
||||
onTap: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
_toggleEmployee(emp);
|
||||
},
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
@override
|
||||
|
||||
@ -24,7 +24,6 @@ class _AddServiceProjectJobBottomSheetState
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final controller = Get.put(AddServiceProjectJobController());
|
||||
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
late RxList<EmployeeModel> _selectedEmployees;
|
||||
|
||||
@override
|
||||
@ -36,7 +35,6 @@ class _AddServiceProjectJobBottomSheetState
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.dispose();
|
||||
Get.delete<AddServiceProjectJobController>();
|
||||
super.dispose();
|
||||
}
|
||||
@ -91,6 +89,7 @@ class _AddServiceProjectJobBottomSheetState
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Widget _employeeSelector() => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -109,13 +108,12 @@ class _AddServiceProjectJobBottomSheetState
|
||||
);
|
||||
|
||||
if (selectedEmployees != null) {
|
||||
setState(() {
|
||||
_selectedEmployees.assignAll(selectedEmployees);
|
||||
});
|
||||
controller.selectedAssignees.assignAll(selectedEmployees);
|
||||
}
|
||||
},
|
||||
child: AbsorbPointer(
|
||||
child: TextFormField(
|
||||
child: Obx(() => TextFormField(
|
||||
decoration: _inputDecoration("Select Employees"),
|
||||
controller: TextEditingController(
|
||||
text: _selectedEmployees.isEmpty
|
||||
@ -127,9 +125,25 @@ class _AddServiceProjectJobBottomSheetState
|
||||
validator: (v) => _selectedEmployees.isEmpty
|
||||
? "Please select employees"
|
||||
: null,
|
||||
)),
|
||||
),
|
||||
),
|
||||
MySpacing.height(8),
|
||||
Obx(() => Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
children: _selectedEmployees
|
||||
.map(
|
||||
(emp) => Chip(
|
||||
label: Text('${emp.firstName} ${emp.lastName}'),
|
||||
onDeleted: () {
|
||||
_selectedEmployees.remove(emp);
|
||||
controller.selectedAssignees.remove(emp);
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
)),
|
||||
],
|
||||
);
|
||||
|
||||
@ -138,9 +152,9 @@ class _AddServiceProjectJobBottomSheetState
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 48,
|
||||
child: TextField(
|
||||
child: TextFormField(
|
||||
controller: controller.tagCtrl,
|
||||
onSubmitted: (v) {
|
||||
onFieldSubmitted: (v) {
|
||||
final value = v.trim();
|
||||
if (value.isNotEmpty &&
|
||||
!controller.enteredTags.contains(value)) {
|
||||
@ -149,6 +163,9 @@ class _AddServiceProjectJobBottomSheetState
|
||||
controller.tagCtrl.clear();
|
||||
},
|
||||
decoration: _inputDecoration("Start typing to add tags"),
|
||||
validator: (v) => controller.enteredTags.isEmpty
|
||||
? "Please add at least one tag"
|
||||
: null,
|
||||
),
|
||||
),
|
||||
MySpacing.height(8),
|
||||
@ -157,24 +174,13 @@ class _AddServiceProjectJobBottomSheetState
|
||||
children: controller.enteredTags
|
||||
.map((tag) => Chip(
|
||||
label: Text(tag),
|
||||
onDeleted: () => controller.enteredTags.remove(tag)))
|
||||
onDeleted: () => controller.enteredTags.remove(tag),
|
||||
))
|
||||
.toList(),
|
||||
)),
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
|
||||
void _toggleEmployee(EmployeeModel emp) {
|
||||
final contains = _selectedEmployees.contains(emp);
|
||||
if (contains) {
|
||||
_selectedEmployees.remove(emp);
|
||||
} else {
|
||||
_selectedEmployees.add(emp);
|
||||
}
|
||||
controller.toggleAssignee(emp);
|
||||
}
|
||||
|
||||
void _handleSubmit() {
|
||||
if (!(formKey.currentState?.validate() ?? false)) return;
|
||||
controller.titleCtrl.text = controller.titleCtrl.text.trim();
|
||||
@ -195,25 +201,9 @@ class _AddServiceProjectJobBottomSheetState
|
||||
children: [
|
||||
_textField("Title", controller.titleCtrl, required: true),
|
||||
MySpacing.height(16),
|
||||
Obx(() {
|
||||
if (_searchController.text.isNotEmpty)
|
||||
return const SizedBox.shrink();
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
children: _selectedEmployees
|
||||
.map(
|
||||
(emp) => Chip(
|
||||
label: Text('${emp.firstName} ${emp.lastName}'),
|
||||
onDeleted: () => _toggleEmployee(emp),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}),
|
||||
_employeeSelector(),
|
||||
MySpacing.height(16),
|
||||
MyText.labelMedium("Tags (Optional)"),
|
||||
_labelWithStar("Tags", required: true),
|
||||
MySpacing.height(8),
|
||||
_tagInput(),
|
||||
MySpacing.height(16),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user