import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:get/get.dart'; import 'package:marco/controller/project_controller.dart'; import 'package:marco/controller/dynamicMenu/dynamic_menu_controller.dart'; import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:marco/helpers/widgets/my_card.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/helpers/widgets/dashbaord/expense_breakdown_chart.dart'; import 'package:marco/helpers/widgets/dashbaord/expense_by_status_widget.dart'; import 'package:marco/helpers/widgets/dashbaord/monthly_expense_dashboard_chart.dart'; import 'package:marco/controller/dashboard/dashboard_controller.dart'; import 'package:marco/helpers/utils/permission_constants.dart'; import 'package:marco/model/dynamicMenu/dynamic_menu_model.dart'; class FinanceScreen extends StatefulWidget { const FinanceScreen({super.key}); @override State createState() => _FinanceScreenState(); } class _FinanceScreenState extends State with UIMixin, TickerProviderStateMixin { final projectController = Get.find(); final DynamicMenuController menuController = Get.put(DynamicMenuController()); late AnimationController _animationController; late Animation _fadeAnimation; final DashboardController dashboardController = Get.put(DashboardController(), permanent: true); @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); _fadeAnimation = CurvedAnimation( parent: _animationController, curve: Curves.easeInOut, ); _animationController.forward(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF8F9FA), appBar: PreferredSize( preferredSize: const Size.fromHeight(72), child: AppBar( backgroundColor: const Color(0xFFF5F5F5), elevation: 0.5, automaticallyImplyLeading: false, titleSpacing: 0, title: Padding( padding: MySpacing.xy(16, 0), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ IconButton( icon: const Icon(Icons.arrow_back_ios_new, color: Colors.black, size: 20), onPressed: () => Get.offNamed('/dashboard'), ), MySpacing.width(8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ MyText.titleLarge( 'Finance', fontWeight: 700, color: Colors.black, ), MySpacing.height(2), GetBuilder( builder: (projectController) { final projectName = projectController.selectedProject?.name ?? 'Select Project'; return Row( children: [ const Icon(Icons.work_outline, size: 14, color: Colors.grey), MySpacing.width(4), Expanded( child: MyText.bodySmall( projectName, fontWeight: 600, overflow: TextOverflow.ellipsis, color: Colors.grey[700], ), ), ], ); }, ), ], ), ), ], ), ), ), ), body: FadeTransition( opacity: _fadeAnimation, child: Obx(() { if (menuController.isLoading.value) { return const Center(child: CircularProgressIndicator()); } if (menuController.hasError.value || menuController.menuItems.isEmpty) { return const Center( child: Text( "Failed to load menus. Please try again later.", style: TextStyle(color: Colors.red), ), ); } // Filter allowed Finance menus dynamically final financeMenuIds = [ MenuItems.expenseReimbursement, MenuItems.paymentRequests, MenuItems.advancePaymentStatements, ]; final financeMenus = menuController.menuItems .where((m) => financeMenuIds.contains(m.id) && m.available) .toList(); if (financeMenus.isEmpty) { return const Center( child: Text( "You don’t have access to the Finance section.", style: TextStyle(color: Colors.grey), ), ); } return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( children: [ _buildFinanceModulesCompact(financeMenus), MySpacing.height(24), ExpenseByStatusWidget(controller: dashboardController), MySpacing.height(24), ExpenseTypeReportChart(), MySpacing.height(24), MonthlyExpenseDashboardChart(), ], ), ); }), ), ); } // --- Finance Modules (Compact Dashboard-style) --- Widget _buildFinanceModulesCompact(List financeMenus) { // Map menu IDs to icon + color final Map financeCardMeta = { MenuItems.expenseReimbursement: _FinanceCardMeta(LucideIcons.badge_dollar_sign, contentTheme.info), MenuItems.paymentRequests: _FinanceCardMeta(LucideIcons.receipt_text, contentTheme.primary), MenuItems.advancePaymentStatements: _FinanceCardMeta(LucideIcons.wallet, contentTheme.warning), }; // Build the stat items using API-provided mobileLink final stats = financeMenus.map((menu) { final meta = financeCardMeta[menu.id]!; // --- Log the routing info --- debugPrint( "[Finance Card] ID: ${menu.id}, Title: ${menu.name}, Route: ${menu.mobileLink}"); return _FinanceStatItem( meta.icon, menu.name, meta.color, menu.mobileLink, // Each card navigates to its own route ); }).toList(); final projectSelected = projectController.selectedProject != null; return LayoutBuilder(builder: (context, constraints) { // Determine number of columns dynamically int crossAxisCount = (constraints.maxWidth ~/ 80).clamp(2, 4); double cardWidth = (constraints.maxWidth - (crossAxisCount - 1) * 6) / crossAxisCount; return Wrap( spacing: 6, runSpacing: 6, alignment: WrapAlignment.end, children: stats .map((stat) => _buildFinanceModuleCard(stat, projectSelected, cardWidth)) .toList(), ); }); } Widget _buildFinanceModuleCard( _FinanceStatItem stat, bool isProjectSelected, double width) { return Opacity( opacity: isProjectSelected ? 1.0 : 0.4, // Dim if no project selected child: IgnorePointer( ignoring: !isProjectSelected, child: InkWell( onTap: () => _onCardTap(stat, isProjectSelected), borderRadius: BorderRadius.circular(5), child: MyCard.bordered( width: width, height: 60, paddingAll: 4, borderRadiusAll: 5, border: Border.all(color: Colors.grey.withOpacity(0.15)), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: stat.color.withOpacity(0.1), borderRadius: BorderRadius.circular(4), ), child: Icon( stat.icon, size: 16, color: stat.color, ), ), MySpacing.height(4), Flexible( child: Text( stat.title, textAlign: TextAlign.center, style: const TextStyle( fontSize: 10, overflow: TextOverflow.ellipsis, ), maxLines: 2, softWrap: true, ), ), ], ), ), ), ), ); } void _onCardTap(_FinanceStatItem statItem, bool isEnabled) { if (!isEnabled) { Get.defaultDialog( title: "No Project Selected", middleText: "Please select a project before accessing this section.", confirm: ElevatedButton( onPressed: () => Get.back(), child: const Text("OK"), ), ); } else { // Navigate to the card's specific route Get.toNamed(statItem.route); } } } class _FinanceStatItem { final IconData icon; final String title; final Color color; final String route; _FinanceStatItem(this.icon, this.title, this.color, this.route); } class _FinanceCardMeta { final IconData icon; final Color color; _FinanceCardMeta(this.icon, this.color); }