marco.pms.mobileapp/lib/view/expense/expense_screen.dart

129 lines
4.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:marco/controller/project_controller.dart';
import 'package:marco/controller/expense/expense_screen_controller.dart';
import 'package:marco/controller/permission_controller.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/my_custom_skeleton.dart';
import 'package:marco/model/expense/expense_list_model.dart';
import 'package:marco/model/expense/add_expense_bottom_sheet.dart';
import 'package:marco/view/expense/expense_filter_bottom_sheet.dart';
import 'package:marco/helpers/widgets/expense_main_components.dart';
import 'package:marco/helpers/utils/permission_constants.dart';
class ExpenseMainScreen extends StatefulWidget {
const ExpenseMainScreen({super.key});
@override
State<ExpenseMainScreen> createState() => _ExpenseMainScreenState();
}
class _ExpenseMainScreenState extends State<ExpenseMainScreen> {
bool isHistoryView = false;
final searchController = TextEditingController();
final expenseController = Get.put(ExpenseController());
final projectController = Get.find<ProjectController>();
final permissionController = Get.find<PermissionController>();
@override
void initState() {
super.initState();
expenseController.fetchExpenses();
}
void _refreshExpenses() => expenseController.fetchExpenses();
void _openFilterBottomSheet() {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (_) => ExpenseFilterBottomSheet(
expenseController: expenseController,
scrollController: ScrollController(),
),
);
}
List<ExpenseModel> _getFilteredExpenses() {
final query = searchController.text.trim().toLowerCase();
final now = DateTime.now();
final filtered = expenseController.expenses.where((e) {
return query.isEmpty ||
e.expensesType.name.toLowerCase().contains(query) ||
e.supplerName.toLowerCase().contains(query) ||
e.paymentMode.name.toLowerCase().contains(query);
}).toList()
..sort((a, b) => b.transactionDate.compareTo(a.transactionDate));
return isHistoryView
? filtered
.where((e) =>
e.transactionDate.isBefore(DateTime(now.year, now.month)))
.toList()
: filtered
.where((e) =>
e.transactionDate.month == now.month &&
e.transactionDate.year == now.year)
.toList();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: ExpenseAppBar(projectController: projectController),
body: SafeArea(
child: Column(
children: [
SearchAndFilter(
controller: searchController,
onChanged: (_) => setState(() {}),
onFilterTap: _openFilterBottomSheet,
onRefreshTap: _refreshExpenses,
expenseController: expenseController,
),
ToggleButtonsRow(
isHistoryView: isHistoryView,
onToggle: (v) => setState(() => isHistoryView = v),
),
Expanded(
child: Obx(() {
if (expenseController.isLoading.value) {
return SkeletonLoaders.expenseListSkeletonLoader();
}
if (expenseController.errorMessage.isNotEmpty) {
return Center(
child: MyText.bodyMedium(
expenseController.errorMessage.value,
color: Colors.red,
),
);
}
final filteredList = _getFilteredExpenses();
return ExpenseList(
expenseList: filteredList,
onViewDetail: () => expenseController.fetchExpenses(),
);
}),
),
],
),
),
// ✅ FAB only if user has expenseUpload permission
floatingActionButton: permissionController
.hasPermission(Permissions.expenseUpload)
? FloatingActionButton(
backgroundColor: Colors.red,
onPressed: showAddExpenseBottomSheet,
child: const Icon(Icons.add, color: Colors.white),
)
: null,
);
}
}