diff --git a/lib/model/dailyTaskPlanning/assign_task_bottom_sheet .dart b/lib/model/dailyTaskPlanning/assign_task_bottom_sheet .dart index 903dc2d..ce19774 100644 --- a/lib/model/dailyTaskPlanning/assign_task_bottom_sheet .dart +++ b/lib/model/dailyTaskPlanning/assign_task_bottom_sheet .dart @@ -48,8 +48,6 @@ class _AssignTaskBottomSheetState extends State { final DailyTaskPlanningController controller = Get.find(); final ProjectController projectController = Get.find(); - final OrganizationController orgController = - Get.put(OrganizationController()); final OrganizationController orgController = Get.put(OrganizationController()); final ServiceController serviceController = Get.put(ServiceController()); @@ -235,8 +233,6 @@ class _AssignTaskBottomSheetState extends State { } void _onRoleMenuPressed() { - final RenderBox overlay = - Overlay.of(context).context.findRenderObject() as RenderBox; final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox; final Size screenSize = overlay.size; @@ -320,9 +316,6 @@ class _AssignTaskBottomSheetState extends State { validator: (value) => this .controller .formFieldValidator(value, fieldType: validatorType), - validator: (value) => this - .controller - .formFieldValidator(value, fieldType: validatorType), ), ], ); diff --git a/lib/model/employees/multiple_select_role_bottomsheet.dart b/lib/model/employees/multiple_select_role_bottomsheet.dart index d51f378..a1f4951 100644 --- a/lib/model/employees/multiple_select_role_bottomsheet.dart +++ b/lib/model/employees/multiple_select_role_bottomsheet.dart @@ -216,222 +216,3 @@ class _MultipleSelectRoleBottomSheetState ); } } - -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(); - } - - 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())), - ); - } - - _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 { - // Single selection → return immediately - Get.back(result: [emp]); - } - - _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, - ), - ), - ), - ); - - @override - Widget build(BuildContext context) { - return BaseBottomSheet( - title: widget.title, - onCancel: () => Get.back(), - onSubmit: () => Get.back(result: _selected.toList()), // Return plain list - child: SizedBox( - height: MediaQuery.of(context).size.height * 0.55, - child: Column( - children: [ - _searchBar(), - 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), - fillColor: - MaterialStateProperty.resolveWith((states) { - if (states.contains(MaterialState.selected)) { - return Colors.blueAccent; - } - return Colors.white; - }), - checkColor: Colors.white, - side: const BorderSide(color: Colors.grey), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 4, - vertical: 6, - ), - ); - }, - ); - }), - ), - ], - ), - ), - ); - } -} diff --git a/lib/model/finance/add_payment_request_bottom_sheet.dart b/lib/model/finance/add_payment_request_bottom_sheet.dart index 9c72a81..9e224b4 100644 --- a/lib/model/finance/add_payment_request_bottom_sheet.dart +++ b/lib/model/finance/add_payment_request_bottom_sheet.dart @@ -11,6 +11,8 @@ import 'package:marco/helpers/widgets/expense/expense_form_widgets.dart'; import 'package:marco/helpers/widgets/my_confirmation_dialog.dart'; import 'package:marco/model/employees/multiple_select_bottomsheet.dart'; import 'package:marco/model/employees/employee_model.dart'; +import 'package:marco/model/employees/multiple_select_bottomsheet.dart'; +import 'package:marco/model/employees/employee_model.dart'; Future showPaymentRequestBottomSheet({ bool isEdit = false, @@ -263,6 +265,35 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet> _gap(), _buildPayeeField(), _gap(), + _buildDropdown( + key: _categoryDropdownKey, + ), + _gap(), + _buildTextField("Title", Icons.title_outlined, + controller.titleController, + hint: "Enter title", + validator: Validators.requiredField), + _gap(), + _buildRadio( + "Is Advance Payment", + Icons.attach_money_outlined, + controller.isAdvancePayment, + ["Yes", "No"]), + _gap(), + _buildDueDateField(), + _gap(), + _buildTextField("Amount", Icons.currency_rupee, + controller.amountController, + hint: "Enter Amount", + keyboardType: TextInputType.number, + validator: (v) => (v != null && + v.isNotEmpty && + double.tryParse(v) != null) + ? null + : "Enter valid amount"), + _gap(), + _buildPayeeField(), + _gap(), _buildDropdown( "Currency", Icons.monetization_on_outlined, @@ -416,6 +447,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet> ); } + Widget _buildPayeeField() { Widget _buildPayeeField() { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -426,6 +458,27 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet> requiredField: true, ), MySpacing.height(6), + GestureDetector( + onTap: _showPayeeSelector, + child: TileContainer( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Obx(() => Text( + controller.selectedPayee.value?.name ?? "Select Payee", + style: const TextStyle(fontSize: 15), + overflow: TextOverflow.ellipsis, + )), + ), + const Icon(Icons.arrow_drop_down, size: 22), + ], + const SectionTitle( + icon: Icons.person_outline, + title: "Payee", + requiredField: true, + ), + MySpacing.height(6), GestureDetector( onTap: _showPayeeSelector, child: TileContainer( @@ -445,6 +498,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet> ), ), const SizedBox(height: 6), + const SizedBox(height: 6), ], ); } @@ -563,6 +617,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet> if (controller.selectedCategory.value == null) { return _showError("Please select a category"); } + if (controller.selectedPayee.value == null) { if (controller.selectedPayee.value == null) { return _showError("Please select a payee"); } @@ -591,6 +646,25 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet> } } + Future _showPayeeSelector() async { + final result = await showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (_) => EmployeeSelectionBottomSheet( + title: "Select Payee", + multipleSelection: false, + initiallySelected: controller.selectedPayee.value != null + ? [controller.selectedPayee.value!] + : [], + ), + ); + + if (result is EmployeeModel) { + controller.selectedPayee.value = result; + } + } + bool _showError(String msg) { showAppSnackbar(title: "Error", message: msg, type: SnackbarType.error); return false; diff --git a/lib/view/finance/advance_payment_screen.dart b/lib/view/finance/advance_payment_screen.dart index b34bf40..3dc8311 100644 --- a/lib/view/finance/advance_payment_screen.dart +++ b/lib/view/finance/advance_payment_screen.dart @@ -52,6 +52,7 @@ class _AdvancePaymentScreenState extends State @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: const Color(0xFFF5F5F5), backgroundColor: const Color(0xFFF5F5F5), appBar: _buildAppBar(), body: SafeArea( @@ -448,6 +449,7 @@ class _AdvancePaymentScreenState extends State : (dateStr.isNotEmpty ? dateStr : '—'); + final project = item.name ?? ''; final desc = item.title ?? ''; final amount = (item.amount ?? 0).toDouble(); @@ -478,6 +480,7 @@ class _AdvancePaymentScreenState extends State TextStyle(fontSize: 12, color: Colors.grey.shade600), ), + ], ), const SizedBox(height: 4), diff --git a/lib/view/layouts/user_profile_right_bar.dart b/lib/view/layouts/user_profile_right_bar.dart index d44e22d..2e74c1a 100644 --- a/lib/view/layouts/user_profile_right_bar.dart +++ b/lib/view/layouts/user_profile_right_bar.dart @@ -15,18 +15,7 @@ import 'package:on_field_work/helpers/services/tenant_service.dart'; import 'package:on_field_work/view/tenant/tenant_selection_screen.dart'; import 'package:on_field_work/controller/tenant/tenant_switch_controller.dart'; import 'package:on_field_work/helpers/theme/theme_editor_widget.dart'; -import 'package:marco/helpers/services/storage/local_storage.dart'; -import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; -import 'package:marco/helpers/widgets/my_spacing.dart'; -import 'package:marco/helpers/widgets/my_text.dart'; -import 'package:marco/helpers/widgets/avatar.dart'; -import 'package:marco/model/employees/employee_info.dart'; -import 'package:marco/controller/auth/mpin_controller.dart'; -import 'package:marco/view/employees/employee_profile_screen.dart'; -import 'package:marco/helpers/services/tenant_service.dart'; -import 'package:marco/view/tenant/tenant_selection_screen.dart'; -import 'package:marco/controller/tenant/tenant_switch_controller.dart'; -import 'package:marco/helpers/theme/theme_editor_widget.dart'; + class UserProfileBar extends StatefulWidget { final bool isCondensed; @@ -101,7 +90,6 @@ class _UserProfileBarState extends State bottom: true, child: Stack( children: [ - // ======================= MAIN PROFILE SIDEBAR ======================= // ======================= MAIN PROFILE SIDEBAR ======================= Offstage( offstage: _isThemeEditorVisible, @@ -147,49 +135,6 @@ class _UserProfileBarState extends State ), ), - // ======================= THEME EDITOR VIEW ======================= - child: LayoutBuilder( - builder: (context, constraints) { - return SingleChildScrollView( - physics: const ClampingScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: constraints.maxHeight), - child: IntrinsicHeight( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - _isLoading - ? const _LoadingSection() - : _userProfileSection(isCondensed), - if (!_isLoading && !isCondensed) - _switchTenantRow(), - MySpacing.height(12), - Divider( - indent: 18, - endIndent: 18, - thickness: 0.7, - color: Colors.grey.withOpacity(0.25), - ), - MySpacing.height(12), - _supportAndSettingsMenu(isCondensed), - const Spacer(), - Divider( - indent: 18, - endIndent: 18, - thickness: 0.35, - color: Colors.grey.withOpacity(0.18), - ), - _logoutButton(isCondensed), - ], - ), - ), - ), - ); - }, - ), - ), - // ======================= THEME EDITOR VIEW ======================= Offstage( offstage: !_isThemeEditorVisible, @@ -313,7 +258,7 @@ class _UserProfileBarState extends State child: const Center(child: CircularProgressIndicator(strokeWidth: 2)), ); - // ⭐ FIXED — YOUR ORIGINAL INTENT, COMPLETED PROPERLY + Widget _noTenantContainer() => Container( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), decoration: BoxDecoration(