resolved reabse conflicts

This commit is contained in:
Manish 2025-11-24 12:37:08 +05:30
parent 2bda44dd19
commit b461d5c2a9
9 changed files with 229 additions and 467 deletions

View File

@ -8,13 +8,13 @@ import 'package:image_picker/image_picker.dart';
import 'package:mime/mime.dart'; import 'package:mime/mime.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:marco/helpers/services/api_service.dart'; import 'package:on_field_work/helpers/services/api_service.dart';
import 'package:marco/helpers/services/app_logger.dart'; import 'package:on_field_work/helpers/services/app_logger.dart';
import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:on_field_work/helpers/widgets/my_snackbar.dart';
import 'package:marco/helpers/widgets/time_stamp_image_helper.dart'; import 'package:on_field_work/helpers/widgets/time_stamp_image_helper.dart';
import 'package:marco/model/finance/expense_category_model.dart'; import 'package:on_field_work/model/finance/expense_category_model.dart';
import 'package:marco/model/finance/currency_list_model.dart'; import 'package:on_field_work/model/finance/currency_list_model.dart';
import 'package:marco/model/employees/employee_model.dart'; import 'package:on_field_work/model/employees/employee_model.dart';
class AddPaymentRequestController extends GetxController { class AddPaymentRequestController extends GetxController {
// Loading States // Loading States

View File

@ -3,20 +3,20 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:marco/controller/task_Planning/daily_task_Planning_controller.dart'; import 'package:on_field_work/controller/task_Planning/daily_task_Planning_controller.dart';
import 'package:marco/controller/project_controller.dart'; import 'package:on_field_work/controller/project_controller.dart';
import 'package:marco/controller/tenant/organization_selection_controller.dart'; import 'package:on_field_work/controller/tenant/organization_selection_controller.dart';
import 'package:marco/controller/tenant/service_controller.dart'; import 'package:on_field_work/controller/tenant/service_controller.dart';
import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:on_field_work/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart'; import 'package:on_field_work/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:on_field_work/helpers/widgets/my_snackbar.dart';
import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:on_field_work/helpers/utils/base_bottom_sheet.dart';
import 'package:marco/helpers/widgets/tenant/organization_selector.dart'; import 'package:on_field_work/helpers/widgets/tenant/organization_selector.dart';
import 'package:marco/helpers/widgets/tenant/service_selector.dart'; import 'package:on_field_work/helpers/widgets/tenant/service_selector.dart';
import 'package:marco/model/attendance/organization_per_project_list_model.dart'; import 'package:on_field_work/model/attendance/organization_per_project_list_model.dart';
import 'package:marco/model/tenant/tenant_services_model.dart'; import 'package:on_field_work/model/tenant/tenant_services_model.dart';
import 'package:marco/model/employees/employee_model.dart'; import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:marco/model/employees/multiple_select_role_bottomsheet.dart'; import 'package:on_field_work/model/employees/multiple_select_role_bottomsheet.dart';
class AssignTaskBottomSheet extends StatefulWidget { class AssignTaskBottomSheet extends StatefulWidget {
final String workLocation; final String workLocation;

View File

@ -1,15 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:marco/controller/directory/manage_bucket_controller.dart'; import 'package:on_field_work/controller/directory/manage_bucket_controller.dart';
import 'package:marco/controller/directory/directory_controller.dart'; import 'package:on_field_work/controller/directory/directory_controller.dart';
import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:on_field_work/helpers/utils/base_bottom_sheet.dart';
import 'package:marco/helpers/widgets/my_text.dart'; import 'package:on_field_work/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:on_field_work/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:on_field_work/helpers/widgets/my_snackbar.dart';
import 'package:marco/model/employees/employee_model.dart'; import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:marco/model/directory/contact_bucket_list_model.dart'; import 'package:on_field_work/model/directory/contact_bucket_list_model.dart';
import 'package:marco/model/employees/multiple_select_bottomsheet.dart'; import 'package:on_field_work/model/employees/multiple_select_bottomsheet.dart';
class EditBucketBottomSheet { class EditBucketBottomSheet {
static void show( static void show(

View File

@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:on_field_work/helpers/utils/base_bottom_sheet.dart';
import 'package:marco/helpers/widgets/my_custom_skeleton.dart'; import 'package:on_field_work/helpers/widgets/my_custom_skeleton.dart';
import 'package:marco/model/employees/employee_model.dart'; import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:marco/controller/task_Planning/daily_task_Planning_controller.dart'; import 'package:on_field_work/controller/task_Planning/daily_task_Planning_controller.dart';
class MultipleSelectRoleBottomSheet extends StatefulWidget { class MultipleSelectRoleBottomSheet extends StatefulWidget {
final String title; final String title;

View File

@ -1,19 +1,19 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:marco/controller/expense/add_expense_controller.dart'; import 'package:on_field_work/controller/expense/add_expense_controller.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:on_field_work/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/model/expense/expense_type_model.dart'; import 'package:on_field_work/model/expense/expense_type_model.dart';
import 'package:marco/model/expense/payment_types_model.dart'; import 'package:on_field_work/model/expense/payment_types_model.dart';
// import 'package:marco/model/expense/employee_selector_bottom_sheet.dart'; // import 'package:on_field_work/model/expense/employee_selector_bottom_sheet.dart';
import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:on_field_work/helpers/utils/base_bottom_sheet.dart';
import 'package:marco/helpers/utils/validators.dart'; import 'package:on_field_work/helpers/utils/validators.dart';
import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:on_field_work/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:on_field_work/helpers/widgets/my_snackbar.dart';
import 'package:marco/helpers/widgets/my_confirmation_dialog.dart'; import 'package:on_field_work/helpers/widgets/my_confirmation_dialog.dart';
import 'package:marco/helpers/widgets/expense/expense_form_widgets.dart'; import 'package:on_field_work/helpers/widgets/expense/expense_form_widgets.dart';
import 'package:marco/model/employees/employee_model.dart'; import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:marco/model/employees/multiple_select_bottomsheet.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>({

View File

@ -1,18 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:marco/controller/finance/add_payment_request_controller.dart'; import 'package:on_field_work/controller/finance/add_payment_request_controller.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:on_field_work/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:on_field_work/helpers/utils/base_bottom_sheet.dart';
import 'package:marco/helpers/utils/validators.dart'; import 'package:on_field_work/helpers/utils/validators.dart';
import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:on_field_work/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:on_field_work/helpers/widgets/my_snackbar.dart';
import 'package:marco/helpers/widgets/expense/expense_form_widgets.dart'; import 'package:on_field_work/helpers/widgets/expense/expense_form_widgets.dart';
import 'package:marco/helpers/widgets/my_confirmation_dialog.dart'; import 'package:on_field_work/helpers/widgets/my_confirmation_dialog.dart';
import 'package:marco/model/employees/multiple_select_bottomsheet.dart'; import 'package:on_field_work/model/employees/multiple_select_bottomsheet.dart';
import 'package:marco/model/employees/employee_model.dart'; import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:marco/model/employees/multiple_select_bottomsheet.dart';
import 'package:marco/model/employees/employee_model.dart';
Future<T?> showPaymentRequestBottomSheet<T>({ Future<T?> showPaymentRequestBottomSheet<T>({
bool isEdit = false, bool isEdit = false,
@ -80,10 +78,10 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
'name': data["projectName"], 'name': data["projectName"],
}; };
controller.selectedPayee.value = data["payee"] ?? ""; controller.selectedPayee.value = data["payee"] ?? "";
controller.isAdvancePayment.value = data["isAdvancePayment"] ?? false; controller.isAdvancePayment.value = data["isAdvancePayment"] ?? false;
// When categories and currencies load, set selected ones
everAll([controller.categories, controller.currencies], (_) { everAll([controller.categories, controller.currencies], (_) {
controller.selectedCategory.value = controller.categories controller.selectedCategory.value = controller.categories
.firstWhereOrNull((c) => c.id == data["expenseCategoryId"]); .firstWhereOrNull((c) => c.id == data["expenseCategoryId"]);
@ -117,52 +115,21 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Obx(() => SafeArea( return Obx(
() => SafeArea(
child: Form( child: Form(
key: _formKey, key: _formKey,
child: BaseBottomSheet( child: BaseBottomSheet(
title: widget.isEdit title: widget.isEdit ? "Edit Payment Request" : "Create Payment Request",
? "Edit Payment Request"
: "Create Payment Request",
isSubmitting: controller.isSubmitting.value, isSubmitting: controller.isSubmitting.value,
onCancel: Get.back, onCancel: Get.back,
submitText: "Save as Draft", submitText: "Save as Draft",
onSubmit: () async { onSubmit: () async {
if (_formKey.currentState!.validate() && if (_formKey.currentState!.validate() && _validateSelections()) {
_validateSelections()) {
bool success = false; bool success = false;
if (widget.isEdit && widget.existingData != null) { if (widget.isEdit && widget.existingData != null) {
final requestId = final requestId = widget.existingData!['id']?.toString() ?? '';
widget.existingData!['id']?.toString() ?? '';
if (requestId.isNotEmpty) {
success = await controller.submitEditedPaymentRequest(
requestId: requestId);
} else {
_showError("Invalid Payment Request ID");
return;
}
} else {
success = await controller.submitPaymentRequest();
}
return Obx(() => SafeArea(
child: Form(
key: _formKey,
child: BaseBottomSheet(
title: widget.isEdit
? "Edit Payment Request"
: "Create Payment Request",
isSubmitting: controller.isSubmitting.value,
onCancel: Get.back,
submitText: "Save as Draft",
onSubmit: () async {
if (_formKey.currentState!.validate() &&
_validateSelections()) {
bool success = false;
if (widget.isEdit && widget.existingData != null) {
final requestId =
widget.existingData!['id']?.toString() ?? '';
if (requestId.isNotEmpty) { if (requestId.isNotEmpty) {
success = await controller.submitEditedPaymentRequest( success = await controller.submitEditedPaymentRequest(
requestId: requestId); requestId: requestId);
@ -174,9 +141,6 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
success = await controller.submitPaymentRequest(); success = await controller.submitPaymentRequest();
} }
if (success) {
Get.back();
widget.onUpdated?.call();
if (success) { if (success) {
Get.back(); Get.back();
widget.onUpdated?.call(); widget.onUpdated?.call();
@ -191,23 +155,6 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
} }
} }
}, },
child: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
_buildDropdown(
showAppSnackbar(
title: "Success",
message: widget.isEdit
? "Payment request updated successfully!"
: "Payment request created successfully!",
type: SnackbarType.success,
);
}
}
},
child: SingleChildScrollView( child: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 20), padding: const EdgeInsets.only(bottom: 20),
child: Column( child: Column(
@ -217,23 +164,17 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
_buildDropdown( _buildDropdown(
"Select Project", "Select Project",
Icons.work_outline, Icons.work_outline,
controller.selectedProject.value?['name'] ?? controller.selectedProject.value?['name'] ?? "Select Project",
"Select Project",
controller.globalProjects, controller.globalProjects,
(p) => p['name'], (p) => p['name'],
controller.selectProject, controller.selectProject,
key: _projectDropdownKey, key: _projectDropdownKey,
), ),
_gap(), _gap(),
_buildDropdown(
key: _projectDropdownKey,
),
_gap(),
_buildDropdown( _buildDropdown(
"Expense Category", "Expense Category",
Icons.category_outlined, Icons.category_outlined,
controller.selectedCategory.value?.name ?? controller.selectedCategory.value?.name ?? "Select Category",
"Select Category",
controller.categories, controller.categories,
(c) => c.name, (c) => c.name,
controller.selectCategory, controller.selectCategory,
@ -242,43 +183,10 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
_gap(), _gap(),
_buildTextField("Title", Icons.title_outlined, _buildTextField("Title", Icons.title_outlined,
controller.titleController, controller.titleController,
hint: "Enter title", hint: "Enter title", validator: Validators.requiredField),
validator: Validators.requiredField),
_gap(), _gap(),
_buildRadio( _buildRadio("Is Advance Payment", Icons.attach_money_outlined,
"Is Advance Payment", controller.isAdvancePayment, ["Yes", "No"]),
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(
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(), _gap(),
_buildDueDateField(), _buildDueDateField(),
_gap(), _gap(),
@ -297,8 +205,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
_buildDropdown( _buildDropdown(
"Currency", "Currency",
Icons.monetization_on_outlined, Icons.monetization_on_outlined,
controller.selectedCurrency.value?.currencyName ?? controller.selectedCurrency.value?.currencyName ?? "Select Currency",
"Select Currency",
controller.currencies, controller.currencies,
(c) => c.currencyName, (c) => c.currencyName,
controller.selectCurrency, controller.selectCurrency,
@ -315,23 +222,11 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
MySpacing.height(30), MySpacing.height(30),
], ],
), ),
key: _currencyDropdownKey,
),
_gap(),
_buildTextField("Description", Icons.description_outlined,
controller.descriptionController,
hint: "Enter description",
maxLines: 3,
validator: Validators.requiredField),
_gap(),
_buildAttachmentsSection(),
MySpacing.height(30),
],
), ),
), ),
), ),
), ),
)); );
} }
Widget _buildDropdown<T>(String title, IconData icon, String value, Widget _buildDropdown<T>(String title, IconData icon, String value,
@ -345,7 +240,8 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
DropdownTile( DropdownTile(
key: key, key: key,
title: value, title: value,
onTap: () => _showOptionList(options, getLabel, onSelected, key)), onTap: () => _showOptionList(options, getLabel, onSelected, key),
),
], ],
); );
} }
@ -374,7 +270,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
} }
Widget _buildRadio( Widget _buildRadio(
String title, IconData icon, RxBool controller, List<String> labels) { String title, IconData icon, RxBool controllerBool, List<String> labels) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -394,16 +290,15 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
final label = entry.value; final label = entry.value;
final value = i == 0; final value = i == 0;
return Expanded( return Expanded(
child: RadioListTile<bool>( child: RadioListTile<bool>(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
title: Text(label), title: Text(label),
value: value, value: value,
groupValue: controller.value, groupValue: controllerBool.value,
activeColor: contentTheme.primary, activeColor: contentTheme.primary,
onChanged: (val) => onChanged: (val) =>
val != null ? controller.value = val : null, val != null ? controllerBool.value = val : null,
), ),
); );
}).toList(), }).toList(),
@ -417,9 +312,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SectionTitle( const SectionTitle(
icon: Icons.calendar_today, icon: Icons.calendar_today, title: "Due To Date", requiredField: true),
title: "Due To Date",
requiredField: true),
MySpacing.height(6), MySpacing.height(6),
GestureDetector( GestureDetector(
onTap: () => controller.pickDueDate(context), onTap: () => controller.pickDueDate(context),
@ -447,7 +340,6 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
); );
} }
Widget _buildPayeeField() {
Widget _buildPayeeField() { Widget _buildPayeeField() {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -458,27 +350,6 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
requiredField: true, requiredField: true,
), ),
MySpacing.height(6), 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( GestureDetector(
onTap: _showPayeeSelector, onTap: _showPayeeSelector,
child: TileContainer( child: TileContainer(
@ -498,7 +369,6 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
), ),
), ),
const SizedBox(height: 6), const SizedBox(height: 6),
const SizedBox(height: 6),
], ],
); );
} }
@ -586,8 +456,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
return; return;
} }
final RenderBox button = final RenderBox button = key.currentContext!.findRenderObject() as RenderBox;
key.currentContext!.findRenderObject() as RenderBox;
final RenderBox overlay = final RenderBox overlay =
Overlay.of(context).context.findRenderObject() as RenderBox; Overlay.of(context).context.findRenderObject() as RenderBox;
final position = button.localToGlobal(Offset.zero, ancestor: overlay); final position = button.localToGlobal(Offset.zero, ancestor: overlay);
@ -601,8 +470,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
0), 0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
items: options items: options
.map( .map((opt) => PopupMenuItem<T>(value: opt, child: Text(getLabel(opt))))
(opt) => PopupMenuItem<T>(value: opt, child: Text(getLabel(opt))))
.toList(), .toList(),
); );
@ -617,7 +485,6 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
if (controller.selectedCategory.value == null) { if (controller.selectedCategory.value == null) {
return _showError("Please select a category"); return _showError("Please select a category");
} }
if (controller.selectedPayee.value == null) {
if (controller.selectedPayee.value == null) { if (controller.selectedPayee.value == null) {
return _showError("Please select a payee"); return _showError("Please select a payee");
} }
@ -646,25 +513,6 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
} }
} }
Future<void> _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) { bool _showError(String msg) {
showAppSnackbar(title: "Error", message: msg, type: SnackbarType.error); showAppSnackbar(title: "Error", message: msg, type: SnackbarType.error);
return false; return false;

View File

@ -1,14 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:marco/controller/finance/payment_request_controller.dart'; import 'package:on_field_work/controller/finance/payment_request_controller.dart';
import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:on_field_work/helpers/utils/base_bottom_sheet.dart';
import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:on_field_work/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart'; import 'package:on_field_work/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/my_text_style.dart'; import 'package:on_field_work/helpers/widgets/my_text_style.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:on_field_work/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/helpers/widgets/date_range_picker.dart'; import 'package:on_field_work/helpers/widgets/date_range_picker.dart';
import 'package:marco/model/employees/employee_model.dart'; import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:marco/model/employees/multiple_select_bottomsheet.dart'; import 'package:on_field_work/model/employees/multiple_select_bottomsheet.dart';
class PaymentRequestFilterBottomSheet extends StatefulWidget { class PaymentRequestFilterBottomSheet extends StatefulWidget {
final PaymentRequestController controller; final PaymentRequestController controller;

View File

@ -2,15 +2,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:marco/controller/expense/expense_screen_controller.dart'; import 'package:on_field_work/controller/expense/expense_screen_controller.dart';
import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:on_field_work/helpers/utils/base_bottom_sheet.dart';
import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:on_field_work/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart'; import 'package:on_field_work/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/my_text_style.dart'; import 'package:on_field_work/helpers/widgets/my_text_style.dart';
import 'package:marco/model/employees/employee_model.dart'; import 'package:on_field_work/model/employees/employee_model.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:on_field_work/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/helpers/widgets/date_range_picker.dart'; import 'package:on_field_work/helpers/widgets/date_range_picker.dart';
import 'package:marco/model/employees/multiple_select_bottomsheet.dart'; import 'package:on_field_work/model/employees/multiple_select_bottomsheet.dart';
class ExpenseFilterBottomSheet extends StatefulWidget { class ExpenseFilterBottomSheet extends StatefulWidget {

View File

@ -35,8 +35,6 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
} }
}); });
_searchCtrl.addListener(() {
controller.searchQuery.value = _searchCtrl.text.trim();
_searchCtrl.addListener(() { _searchCtrl.addListener(() {
controller.searchQuery.value = _searchCtrl.text.trim(); controller.searchQuery.value = _searchCtrl.text.trim();
}); });
@ -52,7 +50,6 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: const Color(0xFFF5F5F5),
backgroundColor: const Color(0xFFF5F5F5), backgroundColor: const Color(0xFFF5F5F5),
appBar: _buildAppBar(), appBar: _buildAppBar(),
body: SafeArea( body: SafeArea(
@ -75,65 +72,18 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
child: GestureDetector( child: GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
onTap: () { onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context); FocusScope.of(context).unfocus();
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
}, },
return RefreshIndicator( child: SingleChildScrollView(
onRefresh: () async {
final emp = controller.selectedEmployee.value;
if (emp != null) {
await controller.fetchAdvancePayments(emp.id.toString());
}
},
color: Colors.white,
backgroundColor: contentTheme.primary,
strokeWidth: 2.5,
displacement: 60,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
},
// ---------------- PORTRAIT (UNCHANGED) ----------------
child: !isLandscape
? SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Container(
color: const Color(0xFFF5F5F5),
child: Column(
children: [
_buildSearchBar(),
_buildEmployeeDropdown(context),
_buildTopBalance(),
_buildPaymentList(),
],
),
),
)
// ---------------- LANDSCAPE (FIXED) ----------------
: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
color: const Color(0xFFF5F5F5), color: const Color(0xFFF5F5F5),
// Removed IntrinsicHeight
// Removed ConstrainedBox
// Dropdown can now open freely
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
_buildSearchBar(), _buildSearchBar(),
_buildEmployeeDropdown( _buildEmployeeDropdown(context),
context), // now overlay works
_buildTopBalance(), _buildTopBalance(),
_buildPaymentList(), _buildPaymentList(),
], ],
@ -223,20 +173,6 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
child: TextField( child: TextField(
controller: _searchCtrl, controller: _searchCtrl,
focusNode: _searchFocus, focusNode: _searchFocus,
onTap: () {
Future.delayed(const Duration(milliseconds: 50), () {
if (mounted) {
FocusScope.of(context).requestFocus(_searchFocus);
}
});
},
onTap: () {
Future.delayed(const Duration(milliseconds: 50), () {
if (mounted) {
FocusScope.of(context).requestFocus(_searchFocus);
}
});
},
decoration: InputDecoration( decoration: InputDecoration(
contentPadding: contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 0), const EdgeInsets.symmetric(horizontal: 12, vertical: 0),
@ -310,17 +246,10 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
return InkWell( return InkWell(
onTap: () { onTap: () {
controller.selectEmployee(e); controller.selectEmployee(e);
_searchCtrl
..text = e.name
..selection = TextSelection.fromPosition(
TextPosition(offset: e.name.length),
);
_searchCtrl _searchCtrl.text = e.name;
..text = e.name _searchCtrl.selection =
..selection = TextSelection.fromPosition( TextSelection.fromPosition(TextPosition(offset: e.name.length));
TextPosition(offset: e.name.length),
);
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
SystemChannels.textInput.invokeMethod('TextInput.hide'); SystemChannels.textInput.invokeMethod('TextInput.hide');
@ -406,7 +335,6 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
); );
} }
// No employee selected yet
if (controller.selectedEmployee.value == null) { if (controller.selectedEmployee.value == null) {
return const Padding( return const Padding(
padding: EdgeInsets.only(top: 100), padding: EdgeInsets.only(top: 100),
@ -414,7 +342,6 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
); );
} }
// Employee selected but no payments found
if (controller.payments.isEmpty) { if (controller.payments.isEmpty) {
return const Padding( return const Padding(
padding: EdgeInsets.only(top: 100), padding: EdgeInsets.only(top: 100),
@ -424,7 +351,6 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
); );
} }
// Payments available
return ListView.builder( return ListView.builder(
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
@ -439,28 +365,27 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
// ---------------- Payment Item ---------------- // ---------------- Payment Item ----------------
Widget _buildPaymentItem(dynamic item) { Widget _buildPaymentItem(dynamic item) {
final dateStr = (item.date ?? '').toString(); final dateStr = (item.date ?? '').toString();
DateTime? parsedDate; DateTime? parsed;
try { try {
parsedDate = DateTime.parse(dateStr); parsed = DateTime.parse(dateStr);
} catch (_) {} } catch (_) {}
final formattedDate = parsedDate != null final formattedDate = parsed != null
? DateFormat('dd MMM yyyy').format(parsedDate) ? DateFormat('dd MMM yyyy').format(parsed)
: (dateStr.isNotEmpty ? dateStr : ''); : (dateStr.isNotEmpty ? dateStr : '');
final project = item.name ?? ''; final project = item.name ?? '';
final desc = item.title ?? ''; final desc = item.title ?? '';
final amount = (item.amount ?? 0).toDouble(); final amount = (item.amount ?? 0).toDouble();
final isCredit = amount >= 0; final isCredit = amount >= 0;
final accentColor = isCredit ? Colors.green.shade700 : Colors.red.shade700; final accent = isCredit ? Colors.green.shade700 : Colors.red.shade700;
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey[100], color: Colors.grey[100],
border: Border( border: const Border(
bottom: BorderSide(color: Color(0xFFE0E0E0), width: 0.9), bottom: BorderSide(color: Color(0xFFE0E0E0), width: 0.9),
), ),
), ),
@ -472,17 +397,9 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Text(formattedDate,
children: [
Text(
formattedDate,
style: style:
TextStyle(fontSize: 12, color: Colors.grey.shade600), TextStyle(fontSize: 12, color: Colors.grey.shade600)),
),
],
),
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
project.isNotEmpty ? project : 'No Project', project.isNotEmpty ? project : 'No Project',
@ -497,10 +414,7 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
desc.isNotEmpty ? desc : 'No Details', desc.isNotEmpty ? desc : 'No Details',
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(fontSize: 13, color: Colors.grey.shade700),
fontSize: 13,
color: Colors.grey.shade700,
),
), ),
], ],
), ),
@ -511,7 +425,7 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
style: TextStyle( style: TextStyle(
fontSize: 15, fontSize: 15,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: accentColor, color: accent,
), ),
), ),
], ],
@ -520,16 +434,16 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
} }
// ---------------- Utilities ---------------- // ---------------- Utilities ----------------
String _initials(String? firstName, [String? lastName]) { String _initials(String? first, [String? last]) {
if ((firstName?.isEmpty ?? true) && (lastName?.isEmpty ?? true)) return '?'; if ((first?.isEmpty ?? true) && (last?.isEmpty ?? true)) return '?';
return ((firstName?.isNotEmpty == true ? firstName![0] : '') + return ((first?.isNotEmpty == true ? first![0] : '') +
(lastName?.isNotEmpty == true ? lastName![0] : '')) (last?.isNotEmpty == true ? last![0] : ''))
.toUpperCase(); .toUpperCase();
} }
String _formatAmount(num amount) { String _formatAmount(num amount) {
final format = NumberFormat('#,##,###.##', 'en_IN'); final f = NumberFormat('#,##,###.##', 'en_IN');
return format.format(amount); return f.format(amount);
} }
static Color _avatarColorFor(String name) { static Color _avatarColorFor(String name) {
@ -542,7 +456,7 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
Colors.teal, Colors.teal,
Colors.amber, Colors.amber,
]; ];
final hash = name.codeUnits.fold(0, (p, e) => p + e); final hash = name.codeUnits.fold(0, (p, c) => p + c);
return colors[hash % colors.length]; return colors[hash % colors.length];
} }
} }