reenhancement of employee selector

This commit is contained in:
Manish 2025-11-24 15:00:52 +05:30
parent 5e1379b74b
commit 6b58085434
2 changed files with 52 additions and 23 deletions

View File

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:async';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -50,10 +51,22 @@ class AddExpenseController extends GetxController {
final isEditMode = false.obs; final isEditMode = false.obs;
final isSearchingEmployees = false.obs; final isSearchingEmployees = false.obs;
// --- Paid By (Single + Multi Selection Support) ---
// single selection
final selectedPaidBy = Rxn<EmployeeModel>();
// helper setters
void setSelectedPaidBy(EmployeeModel? emp) {
selectedPaidBy.value = emp;
}
// --- Dropdown Selections & Data --- // --- Dropdown Selections & Data ---
final selectedPaymentMode = Rxn<PaymentModeModel>(); final selectedPaymentMode = Rxn<PaymentModeModel>();
final selectedExpenseType = Rxn<ExpenseTypeModel>(); final selectedExpenseType = Rxn<ExpenseTypeModel>();
final selectedPaidBy = Rxn<EmployeeModel>(); // final selectedPaidBy = Rxn<EmployeeModel>();
final selectedProject = ''.obs; final selectedProject = ''.obs;
final selectedTransactionDate = Rxn<DateTime>(); final selectedTransactionDate = Rxn<DateTime>();

View File

@ -5,13 +5,14 @@ import 'package:on_field_work/controller/expense/add_expense_controller.dart';
import 'package:on_field_work/helpers/utils/mixins/ui_mixin.dart'; import 'package:on_field_work/helpers/utils/mixins/ui_mixin.dart';
import 'package:on_field_work/model/expense/expense_type_model.dart'; import 'package:on_field_work/model/expense/expense_type_model.dart';
import 'package:on_field_work/model/expense/payment_types_model.dart'; import 'package:on_field_work/model/expense/payment_types_model.dart';
import 'package:on_field_work/model/expense/employee_selector_bottom_sheet.dart';
import 'package:on_field_work/helpers/utils/base_bottom_sheet.dart'; import 'package:on_field_work/helpers/utils/base_bottom_sheet.dart';
import 'package:on_field_work/helpers/utils/validators.dart'; import 'package:on_field_work/helpers/utils/validators.dart';
import 'package:on_field_work/helpers/widgets/my_spacing.dart'; 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/helpers/widgets/my_snackbar.dart';
import 'package:on_field_work/helpers/widgets/my_confirmation_dialog.dart'; import 'package:on_field_work/helpers/widgets/my_confirmation_dialog.dart';
import 'package:on_field_work/helpers/widgets/expense/expense_form_widgets.dart'; import 'package:on_field_work/helpers/widgets/expense/expense_form_widgets.dart';
import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:on_field_work/model/employees/multiple_select_bottomsheet.dart';
/// Show bottom sheet wrapper /// Show bottom sheet wrapper
Future<T?> showAddExpenseBottomSheet<T>({ Future<T?> showAddExpenseBottomSheet<T>({
@ -52,24 +53,36 @@ class _AddExpenseBottomSheetState extends State<_AddExpenseBottomSheet>
/// Show employee list /// Show employee list
Future<void> _showEmployeeList() async { Future<void> _showEmployeeList() async {
await showModalBottomSheet( final result = await showModalBottomSheet<dynamic>(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)), borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
), ),
builder: (_) => ReusableEmployeeSelectorBottomSheet( builder: (_) => EmployeeSelectionBottomSheet(
searchController: controller.employeeSearchController, initiallySelected: controller.selectedPaidBy.value != null
searchResults: controller.employeeSearchResults, ? [controller.selectedPaidBy.value!]
isSearching: controller.isSearchingEmployees, : [],
onSearch: controller.searchEmployees, multipleSelection: false,
onSelect: (emp) => controller.selectedPaidBy.value = emp, title: "Select Paid By",
), ),
); );
controller.employeeSearchController.clear(); if (result == null) return;
controller.employeeSearchResults.clear();
// result will be EmployeeModel or [EmployeeModel]
if (result is EmployeeModel) {
controller.setSelectedPaidBy(result);
} else if (result is List && result.isNotEmpty) {
controller.setSelectedPaidBy(result.first as EmployeeModel);
}
// cleanup
try {
controller.employeeSearchController.clear();
controller.employeeSearchResults.clear();
} catch (_) {}
} }
/// Generic option list /// Generic option list
@ -343,23 +356,26 @@ class _AddExpenseBottomSheetState extends State<_AddExpenseBottomSheet>
const SectionTitle( const SectionTitle(
icon: Icons.person_outline, title: "Paid By", requiredField: true), icon: Icons.person_outline, title: "Paid By", requiredField: true),
MySpacing.height(6), MySpacing.height(6),
// Main tile: tap to choose mode + selection sheet
GestureDetector( GestureDetector(
onTap: _showEmployeeList, onTap: _showEmployeeList,
child: TileContainer( child: TileContainer(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Expanded(
controller.selectedPaidBy.value == null child: Text(
? "Select Paid By" controller.selectedPaidBy.value?.name ?? "Select Paid By",
: '${controller.selectedPaidBy.value?.firstName ?? ''} ${controller.selectedPaidBy.value?.lastName ?? ''}', style: TextStyle(fontSize: 15),
style: const TextStyle(fontSize: 14), overflow: TextOverflow.ellipsis,
), ),
const Icon(Icons.arrow_drop_down, size: 22), ),
], Icon(Icons.arrow_drop_down, size: 22),
), ],
), )),
), ),
// small helper: long-press to quickly open multi-select directly (optional)
const SizedBox(height: 6),
], ],
); );
} }