resolved reabse conflicts
This commit is contained in:
parent
2bda44dd19
commit
b461d5c2a9
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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>({
|
||||||
|
|||||||
@ -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,221 +115,118 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Obx(() => SafeArea(
|
return Obx(
|
||||||
child: Form(
|
() => SafeArea(
|
||||||
key: _formKey,
|
child: Form(
|
||||||
child: BaseBottomSheet(
|
key: _formKey,
|
||||||
title: widget.isEdit
|
child: BaseBottomSheet(
|
||||||
? "Edit Payment Request"
|
title: widget.isEdit ? "Edit Payment Request" : "Create 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() && _validateSelections()) {
|
||||||
if (_formKey.currentState!.validate() &&
|
bool success = false;
|
||||||
_validateSelections()) {
|
|
||||||
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) {
|
||||||
if (requestId.isNotEmpty) {
|
success = await controller.submitEditedPaymentRequest(
|
||||||
success = await controller.submitEditedPaymentRequest(
|
requestId: requestId);
|
||||||
requestId: requestId);
|
|
||||||
} else {
|
|
||||||
_showError("Invalid Payment Request ID");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
success = await controller.submitPaymentRequest();
|
_showError("Invalid Payment Request ID");
|
||||||
}
|
return;
|
||||||
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) {
|
|
||||||
success = await controller.submitEditedPaymentRequest(
|
|
||||||
requestId: requestId);
|
|
||||||
} else {
|
|
||||||
_showError("Invalid Payment Request ID");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
success = await controller.submitPaymentRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
Get.back();
|
|
||||||
widget.onUpdated?.call();
|
|
||||||
if (success) {
|
|
||||||
Get.back();
|
|
||||||
widget.onUpdated?.call();
|
|
||||||
|
|
||||||
showAppSnackbar(
|
|
||||||
title: "Success",
|
|
||||||
message: widget.isEdit
|
|
||||||
? "Payment request updated successfully!"
|
|
||||||
: "Payment request created successfully!",
|
|
||||||
type: SnackbarType.success,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
success = await controller.submitPaymentRequest();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
child: SingleChildScrollView(
|
if (success) {
|
||||||
padding: const EdgeInsets.only(bottom: 20),
|
Get.back();
|
||||||
child: Column(
|
widget.onUpdated?.call();
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
showAppSnackbar(
|
||||||
children: [
|
title: "Success",
|
||||||
_buildDropdown(
|
message: widget.isEdit
|
||||||
showAppSnackbar(
|
? "Payment request updated successfully!"
|
||||||
title: "Success",
|
: "Payment request created successfully!",
|
||||||
message: widget.isEdit
|
type: SnackbarType.success,
|
||||||
? "Payment request updated successfully!"
|
);
|
||||||
: "Payment request created successfully!",
|
|
||||||
type: SnackbarType.success,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
child: SingleChildScrollView(
|
},
|
||||||
padding: const EdgeInsets.only(bottom: 20),
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
padding: const EdgeInsets.only(bottom: 20),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
_buildDropdown(
|
children: [
|
||||||
"Select Project",
|
_buildDropdown(
|
||||||
Icons.work_outline,
|
"Select Project",
|
||||||
controller.selectedProject.value?['name'] ??
|
Icons.work_outline,
|
||||||
"Select Project",
|
controller.selectedProject.value?['name'] ?? "Select Project",
|
||||||
controller.globalProjects,
|
controller.globalProjects,
|
||||||
(p) => p['name'],
|
(p) => p['name'],
|
||||||
controller.selectProject,
|
controller.selectProject,
|
||||||
key: _projectDropdownKey,
|
key: _projectDropdownKey,
|
||||||
),
|
),
|
||||||
_gap(),
|
_gap(),
|
||||||
_buildDropdown(
|
_buildDropdown(
|
||||||
key: _projectDropdownKey,
|
"Expense Category",
|
||||||
),
|
Icons.category_outlined,
|
||||||
_gap(),
|
controller.selectedCategory.value?.name ?? "Select Category",
|
||||||
_buildDropdown(
|
controller.categories,
|
||||||
"Expense Category",
|
(c) => c.name,
|
||||||
Icons.category_outlined,
|
controller.selectCategory,
|
||||||
controller.selectedCategory.value?.name ??
|
key: _categoryDropdownKey,
|
||||||
"Select Category",
|
),
|
||||||
controller.categories,
|
_gap(),
|
||||||
(c) => c.name,
|
_buildTextField("Title", Icons.title_outlined,
|
||||||
controller.selectCategory,
|
controller.titleController,
|
||||||
key: _categoryDropdownKey,
|
hint: "Enter title", validator: Validators.requiredField),
|
||||||
),
|
_gap(),
|
||||||
_gap(),
|
_buildRadio("Is Advance Payment", Icons.attach_money_outlined,
|
||||||
_buildTextField("Title", Icons.title_outlined,
|
controller.isAdvancePayment, ["Yes", "No"]),
|
||||||
controller.titleController,
|
_gap(),
|
||||||
hint: "Enter title",
|
_buildDueDateField(),
|
||||||
validator: Validators.requiredField),
|
_gap(),
|
||||||
_gap(),
|
_buildTextField("Amount", Icons.currency_rupee,
|
||||||
_buildRadio(
|
controller.amountController,
|
||||||
"Is Advance Payment",
|
hint: "Enter Amount",
|
||||||
Icons.attach_money_outlined,
|
keyboardType: TextInputType.number,
|
||||||
controller.isAdvancePayment,
|
validator: (v) => (v != null &&
|
||||||
["Yes", "No"]),
|
v.isNotEmpty &&
|
||||||
_gap(),
|
double.tryParse(v) != null)
|
||||||
_buildDueDateField(),
|
? null
|
||||||
_gap(),
|
: "Enter valid amount"),
|
||||||
_buildTextField("Amount", Icons.currency_rupee,
|
_gap(),
|
||||||
controller.amountController,
|
_buildPayeeField(),
|
||||||
hint: "Enter Amount",
|
_gap(),
|
||||||
keyboardType: TextInputType.number,
|
_buildDropdown(
|
||||||
validator: (v) => (v != null &&
|
"Currency",
|
||||||
v.isNotEmpty &&
|
Icons.monetization_on_outlined,
|
||||||
double.tryParse(v) != null)
|
controller.selectedCurrency.value?.currencyName ?? "Select Currency",
|
||||||
? null
|
controller.currencies,
|
||||||
: "Enter valid amount"),
|
(c) => c.currencyName,
|
||||||
_gap(),
|
controller.selectCurrency,
|
||||||
_buildPayeeField(),
|
key: _currencyDropdownKey,
|
||||||
_gap(),
|
),
|
||||||
_buildDropdown(
|
_gap(),
|
||||||
key: _categoryDropdownKey,
|
_buildTextField("Description", Icons.description_outlined,
|
||||||
),
|
controller.descriptionController,
|
||||||
_gap(),
|
hint: "Enter description",
|
||||||
_buildTextField("Title", Icons.title_outlined,
|
maxLines: 3,
|
||||||
controller.titleController,
|
validator: Validators.requiredField),
|
||||||
hint: "Enter title",
|
_gap(),
|
||||||
validator: Validators.requiredField),
|
_buildAttachmentsSection(),
|
||||||
_gap(),
|
MySpacing.height(30),
|
||||||
_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,
|
|
||||||
controller.selectedCurrency.value?.currencyName ??
|
|
||||||
"Select Currency",
|
|
||||||
controller.currencies,
|
|
||||||
(c) => c.currencyName,
|
|
||||||
controller.selectCurrency,
|
|
||||||
key: _currencyDropdownKey,
|
|
||||||
),
|
|
||||||
_gap(),
|
|
||||||
_buildTextField("Description", Icons.description_outlined,
|
|
||||||
controller.descriptionController,
|
|
||||||
hint: "Enter description",
|
|
||||||
maxLines: 3,
|
|
||||||
validator: Validators.requiredField),
|
|
||||||
_gap(),
|
|
||||||
_buildAttachmentsSection(),
|
|
||||||
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,
|
||||||
@ -343,9 +238,10 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
|
|||||||
SectionTitle(icon: icon, title: title, requiredField: true),
|
SectionTitle(icon: icon, title: title, requiredField: true),
|
||||||
MySpacing.height(6),
|
MySpacing.height(6),
|
||||||
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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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,71 +72,24 @@ 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 {
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
final emp = controller.selectedEmployee.value;
|
child: Container(
|
||||||
if (emp != null) {
|
width: double.infinity,
|
||||||
await controller.fetchAdvancePayments(emp.id.toString());
|
color: const Color(0xFFF5F5F5),
|
||||||
}
|
child: Column(
|
||||||
},
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
color: Colors.white,
|
children: [
|
||||||
backgroundColor: contentTheme.primary,
|
_buildSearchBar(),
|
||||||
strokeWidth: 2.5,
|
_buildEmployeeDropdown(context),
|
||||||
displacement: 60,
|
_buildTopBalance(),
|
||||||
child: GestureDetector(
|
_buildPaymentList(),
|
||||||
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(),
|
|
||||||
child: Container(
|
|
||||||
width: double.infinity,
|
|
||||||
color: const Color(0xFFF5F5F5),
|
|
||||||
|
|
||||||
// ❗ Removed IntrinsicHeight
|
|
||||||
// ❗ Removed ConstrainedBox
|
|
||||||
// Dropdown can now open freely
|
|
||||||
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
_buildSearchBar(),
|
|
||||||
_buildEmployeeDropdown(
|
|
||||||
context), // now overlay works
|
|
||||||
_buildTopBalance(),
|
|
||||||
_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: [
|
style:
|
||||||
Text(
|
TextStyle(fontSize: 12, color: Colors.grey.shade600)),
|
||||||
formattedDate,
|
|
||||||
style:
|
|
||||||
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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user