import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:marco/controller/expense/expense_detail_controller.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/helpers/widgets/my_text_style.dart'; import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/model/expense/employee_selector_bottom_sheet.dart'; class ReimbursementBottomSheet extends StatefulWidget { final String expenseId; final String statusId; final void Function() onClose; final Future Function({ required String comment, required String reimburseTransactionId, required String reimburseDate, required String reimburseById, required String statusId, }) onSubmit; const ReimbursementBottomSheet({ super.key, required this.expenseId, required this.onClose, required this.onSubmit, required this.statusId, }); @override State createState() => _ReimbursementBottomSheetState(); } class _ReimbursementBottomSheetState extends State { final ExpenseDetailController controller = Get.find(); final TextEditingController commentCtrl = TextEditingController(); final TextEditingController txnCtrl = TextEditingController(); final RxString dateStr = ''.obs; @override void dispose() { commentCtrl.dispose(); txnCtrl.dispose(); super.dispose(); } void _showEmployeeList() async { await showModalBottomSheet( context: context, isScrollControlled: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), backgroundColor: Colors.transparent, builder: (_) => ReusableEmployeeSelectorBottomSheet( searchController: controller.employeeSearchController, searchResults: controller.employeeSearchResults, isSearching: controller.isSearchingEmployees, onSearch: controller.searchEmployees, onSelect: (emp) => controller.selectedReimbursedBy.value = emp, ), ); // Optional cleanup controller.employeeSearchController.clear(); controller.employeeSearchResults.clear(); } InputDecoration _inputDecoration(String hint) { return InputDecoration( hintText: hint, hintStyle: MyTextStyle.bodySmall(xMuted: true), filled: true, fillColor: Colors.grey.shade100, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade300), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade300), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Colors.blueAccent, width: 1.5), ), contentPadding: MySpacing.all(16), ); } @override Widget build(BuildContext context) { return Obx(() { return BaseBottomSheet( title: "Reimbursement Info", isSubmitting: controller.isLoading.value, onCancel: () { widget.onClose(); Navigator.pop(context); }, onSubmit: () async { if (commentCtrl.text.trim().isEmpty || txnCtrl.text.trim().isEmpty || dateStr.value.isEmpty || controller.selectedReimbursedBy.value == null) { showAppSnackbar( title: "Incomplete", message: "Please fill all fields", type: SnackbarType.warning, ); return; } final success = await widget.onSubmit( comment: commentCtrl.text.trim(), reimburseTransactionId: txnCtrl.text.trim(), reimburseDate: dateStr.value, reimburseById: controller.selectedReimbursedBy.value!.id, statusId: widget.statusId, ); if (success) { Get.back(); showAppSnackbar( title: "Success", message: "Reimbursement submitted", type: SnackbarType.success, ); } else { showAppSnackbar( title: "Error", message: controller.errorMessage.value, type: SnackbarType.error, ); } }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MyText.labelMedium("Comment"), MySpacing.height(8), TextField( controller: commentCtrl, decoration: _inputDecoration("Enter comment"), ), MySpacing.height(16), MyText.labelMedium("Transaction ID"), MySpacing.height(8), TextField( controller: txnCtrl, decoration: _inputDecoration("Enter transaction ID"), ), MySpacing.height(16), MySpacing.height(16), MyText.labelMedium("Reimbursement Date"), MySpacing.height(8), GestureDetector( onTap: () async { final picked = await showDatePicker( context: context, initialDate: dateStr.value.isEmpty ? DateTime.now() : DateFormat('dd MMM yyyy').parse(dateStr.value), firstDate: DateTime(2020), lastDate: DateTime(2100), ); if (picked != null) { dateStr.value = DateFormat('dd MMM yyyy').format(picked); } }, child: AbsorbPointer( child: TextField( controller: TextEditingController(text: dateStr.value), decoration: _inputDecoration("Select Date").copyWith( suffixIcon: const Icon(Icons.calendar_today), ), ), ), ), MySpacing.height(16), MyText.labelMedium("Reimbursed By"), MySpacing.height(8), GestureDetector( onTap: _showEmployeeList, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade300), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( controller.selectedReimbursedBy.value == null ? "Select Paid By" : '${controller.selectedReimbursedBy.value?.firstName ?? ''} ${controller.selectedReimbursedBy.value?.lastName ?? ''}', style: const TextStyle(fontSize: 14), ), const Icon(Icons.arrow_drop_down, size: 22), ], ), ), ), ], ), ); }); } }