reenhancement of employee selector

This commit is contained in:
Manish 2025-11-24 14:56:09 +05:30
parent 3fa578f1b4
commit e2897e4dde
2 changed files with 78 additions and 115 deletions

View File

@ -9,6 +9,7 @@ import 'package:on_field_work/helpers/widgets/my_spacing.dart';
import 'package:on_field_work/helpers/widgets/my_snackbar.dart';
import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:on_field_work/model/directory/contact_bucket_list_model.dart';
import 'package:on_field_work/model/employees/multiple_select_bottomsheet.dart';
class EditBucketBottomSheet {
static void show(
@ -21,10 +22,8 @@ class EditBucketBottomSheet {
final nameController = TextEditingController(text: bucket.name);
final descController = TextEditingController(text: bucket.description);
final searchController = TextEditingController();
final selectedIds = RxSet<String>({...bucket.employeeIds});
final searchText = ''.obs;
InputDecoration _inputDecoration(String label) {
return InputDecoration(
@ -84,6 +83,15 @@ class EditBucketBottomSheet {
}
}
Future<void> _handleSubmitBottomSheet(BuildContext sheetContext) async {
await _handleSubmit();
// close bottom sheet safely
if (Navigator.of(sheetContext).canPop()) {
Navigator.of(sheetContext).pop();
}
}
Widget _formContent() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -101,117 +109,72 @@ class EditBucketBottomSheet {
MySpacing.height(20),
MyText.labelLarge('Shared With', fontWeight: 600),
MySpacing.height(8),
Obx(() => TextField(
controller: searchController,
onChanged: (value) => searchText.value = value.toLowerCase(),
decoration: InputDecoration(
hintText: 'Search employee...',
prefixIcon: const Icon(Icons.search, size: 20),
suffixIcon: searchText.value.isNotEmpty
? IconButton(
icon: const Icon(Icons.clear, size: 18),
onPressed: () {
searchController.clear();
searchText.value = '';
},
)
: null,
isDense: true,
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
filled: true,
fillColor: Colors.grey.shade100,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.grey.shade300),
),
),
)),
MySpacing.height(8),
Obx(() {
final filtered = allEmployees.where((emp) {
final fullName = '${emp.firstName} ${emp.lastName}'.toLowerCase();
return fullName.contains(searchText.value);
}).toList();
if (selectedIds.isEmpty) return const SizedBox.shrink();
return SizedBox(
height: 180,
child: ListView.separated(
itemCount: filtered.length,
separatorBuilder: (_, __) => const SizedBox(height: 2),
itemBuilder: (context, index) {
final emp = filtered[index];
final selectedEmployees =
allEmployees.where((e) => selectedIds.contains(e.id)).toList();
return Wrap(
spacing: 8,
children: selectedEmployees.map((emp) {
final fullName = '${emp.firstName} ${emp.lastName}'.trim();
return Obx(() => Theme(
data: Theme.of(context).copyWith(
unselectedWidgetColor: Colors.grey.shade500,
checkboxTheme: CheckboxThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4)),
side: const BorderSide(color: Colors.grey),
fillColor:
MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return Colors.blueAccent;
}
return Colors.white;
}),
checkColor: MaterialStateProperty.all(Colors.white),
),
),
child: CheckboxListTile(
dense: true,
contentPadding: EdgeInsets.zero,
visualDensity: const VisualDensity(vertical: -4),
controlAffinity: ListTileControlAffinity.leading,
value: selectedIds.contains(emp.id),
onChanged: emp.id == ownerId
return Chip(
label: Text(fullName),
onDeleted: emp.id == ownerId
? null
: (val) {
if (val == true) {
selectedIds.add(emp.id);
} else {
selectedIds.remove(emp.id);
}
},
title: Row(
children: [
Expanded(
child: MyText.bodyMedium(
fullName.isNotEmpty ? fullName : 'Unnamed',
fontWeight: 600,
),
),
if (emp.id == ownerId)
Container(
margin: const EdgeInsets.only(left: 6),
padding: const EdgeInsets.symmetric(
horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.red.shade50,
borderRadius: BorderRadius.circular(4),
),
child: MyText.labelSmall(
"Owner",
fontWeight: 600,
color: Colors.red,
),
),
],
),
subtitle: emp.jobRole.isNotEmpty
? MyText.bodySmall(
emp.jobRole,
color: Colors.grey.shade600,
)
: null,
),
));
},
),
: () => selectedIds.remove(emp.id),
);
}).toList(),
);
}),
MySpacing.height(8),
// --- Open new EmployeeSelectionBottomSheet ---
GestureDetector(
onTap: () async {
final initiallySelected = allEmployees
.where((e) => selectedIds.contains(e.id))
.toList();
final result = await showModalBottomSheet<List<EmployeeModel>>(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(22)),
),
builder: (_) => EmployeeSelectionBottomSheet(
initiallySelected: initiallySelected,
multipleSelection: true,
title: "Shared With",
),
);
if (result != null) {
selectedIds
..clear()
..addAll(result.map((e) => e.id));
}
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.shade300),
),
child: Row(
children: const [
Icon(Icons.search, color: Colors.grey),
SizedBox(width: 8),
Expanded(child: Text("Search & Select Employees")),
],
),
),
),
MySpacing.height(8),
const SizedBox.shrink(),
],
);
}
@ -224,7 +187,7 @@ class EditBucketBottomSheet {
return BaseBottomSheet(
title: "Edit Bucket",
onCancel: () => Navigator.pop(context),
onSubmit: _handleSubmit,
onSubmit: () => _handleSubmitBottomSheet(context),
child: _formContent(),
);
},

View File

@ -1,5 +1,3 @@
// ignore_for_file: must_be_immutable
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:on_field_work/controller/expense/expense_screen_controller.dart';
@ -8,9 +6,10 @@ import 'package:on_field_work/helpers/widgets/my_spacing.dart';
import 'package:on_field_work/helpers/widgets/my_text.dart';
import 'package:on_field_work/helpers/widgets/my_text_style.dart';
import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:on_field_work/model/expense/employee_selector_for_filter_bottom_sheet.dart';
import 'package:on_field_work/helpers/utils/mixins/ui_mixin.dart';
import 'package:on_field_work/helpers/widgets/date_range_picker.dart';
import 'package:on_field_work/model/employees/multiple_select_bottomsheet.dart';
class ExpenseFilterBottomSheet extends StatefulWidget {
final ExpenseController expenseController;
@ -303,12 +302,13 @@ class _ExpenseFilterBottomSheetState extends State<ExpenseFilterBottomSheet>
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (context) => EmployeeSelectorBottomSheet(
selectedEmployees: selectedEmployees,
searchEmployees: searchEmployees,
builder: (context) => EmployeeSelectionBottomSheet(
initiallySelected: selectedEmployees.toList(),
multipleSelection: true,
title: title,
),
);
if (result != null) selectedEmployees.assignAll(result);
},
child: Container(