import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:get/get.dart'; import 'package:marco/controller/dashboard/dashboard_controller.dart'; import 'package:marco/controller/project_controller.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:marco/helpers/widgets/my_card.dart'; import 'package:marco/helpers/widgets/my_container.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/view/dashboard/dashboard_chart.dart'; import 'package:marco/view/layouts/layout.dart'; import 'package:marco/controller/dynamicMenu/dynamic_menu_controller.dart'; import 'package:marco/helpers/widgets/my_custom_skeleton.dart'; // import 'package:marco/helpers/services/firebase/firebase_messaging_service.dart'; // ❌ Commented out class DashboardScreen extends StatefulWidget { const DashboardScreen({super.key}); static const String dashboardRoute = "/dashboard"; static const String employeesRoute = "/dashboard/employees"; static const String projectsRoute = "/dashboard"; static const String attendanceRoute = "/dashboard/attendance"; static const String tasksRoute = "/dashboard/daily-task"; static const String dailyTasksRoute = "/dashboard/daily-task-Planning"; static const String dailyTasksProgressRoute = "/dashboard/daily-task-progress"; static const String directoryMainPageRoute = "/dashboard/directory-main-page"; static const String expenseMainPageRoute = "/dashboard/expense-main-page"; @override State createState() => _DashboardScreenState(); } class _DashboardScreenState extends State with UIMixin { final DashboardController dashboardController = Get.put(DashboardController(), permanent: true); final DynamicMenuController menuController = Get.put(DynamicMenuController(), permanent: true); bool hasMpin = true; @override void initState() { super.initState(); _checkMpinStatus(); } Future _checkMpinStatus() async { hasMpin = await LocalStorage.getIsMpin(); if (mounted) setState(() {}); } @override Widget build(BuildContext context) { return Layout( child: SingleChildScrollView( padding: const EdgeInsets.all(10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ❌ Commented out FCM Test Button /* ElevatedButton( onPressed: () async { final fcmService = FirebaseNotificationService(); final token = await fcmService.getFcmToken(); if (token != null) { await fcmService.sendTestNotification(token); } }, child: const Text("Send Test Notification"), ), MySpacing.height(10), */ _buildDashboardStats(context), MySpacing.height(24), _buildAttendanceChartSection(), ], ), ), ); } /// Dashboard Statistics Section with ProjectController, Obx reactivity for menus Widget _buildDashboardStats(BuildContext context) { return Obx(() { if (menuController.isLoading.value) { return _buildLoadingSkeleton(context); } if (menuController.hasError.value) { return Padding( padding: const EdgeInsets.all(16), child: Center( child: MyText.bodySmall( "Failed to load menus. Please try again later.", color: Colors.red, ), ), ); } final stats = [ _StatItem(LucideIcons.scan_face, "Attendance", contentTheme.success, DashboardScreen.attendanceRoute), _StatItem(LucideIcons.users, "Employees", contentTheme.warning, DashboardScreen.employeesRoute), _StatItem(LucideIcons.logs, "Daily Task Planning", contentTheme.info, DashboardScreen.dailyTasksRoute), _StatItem(LucideIcons.list_todo, "Daily Progress Report", contentTheme.info, DashboardScreen.dailyTasksProgressRoute), _StatItem(LucideIcons.folder, "Directory", contentTheme.info, DashboardScreen.directoryMainPageRoute), _StatItem(LucideIcons.badge_dollar_sign, "Expense", contentTheme.info, DashboardScreen.expenseMainPageRoute), ]; final projectController = Get.find(); final isProjectSelected = projectController.selectedProject != null; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (!isProjectSelected) _buildNoProjectMessage(), LayoutBuilder( builder: (context, constraints) { final maxWidth = constraints.maxWidth; final crossAxisCount = (maxWidth / 100).floor().clamp(2, 4); final cardWidth = (maxWidth - (crossAxisCount - 1) * 10) / crossAxisCount; return Wrap( spacing: 10, runSpacing: 10, children: stats .where((stat) { final isAllowed = menuController.isMenuAllowed(stat.title); // 👇 Log what is being checked debugPrint( "[Dashboard Menu] Checking menu: ${stat.title} -> Allowed: $isAllowed"); return isAllowed; }) .map((stat) => _buildStatCard(stat, cardWidth, isProjectSelected)) .toList(), ); }, ), ], ); }); } /// Attendance Chart Section Widget _buildAttendanceChartSection() { return Obx(() { if (menuController.isLoading.value) { // ✅ Show Skeleton Loader Instead of CircularProgressIndicator return Padding( padding: const EdgeInsets.all(8.0), child: SkeletonLoaders.chartSkeletonLoader(), // <-- using the skeleton we built ); } final isAttendanceAllowed = menuController.isMenuAllowed("Attendance"); if (!isAttendanceAllowed) { // 🚫 Don't render anything if attendance menu is not allowed return const SizedBox.shrink(); } return GetBuilder( id: 'dashboard_controller', builder: (projectController) { final isProjectSelected = projectController.selectedProject != null; return Opacity( opacity: isProjectSelected ? 1.0 : 0.4, child: IgnorePointer( ignoring: !isProjectSelected, child: ClipRRect( borderRadius: BorderRadius.circular(12), child: AttendanceDashboardChart(), ), ), ); }, ); }); } /// No Project Assigned Message Widget _buildNoProjectMessage() { return Padding( padding: const EdgeInsets.symmetric(vertical: 12), child: MyCard( color: Colors.orange.withOpacity(0.1), paddingAll: 12, child: Row( children: [ const Icon(Icons.info_outline, color: Colors.orange), MySpacing.width(8), Expanded( child: MyText.bodySmall( "No projects assigned yet. Please contact your manager to get started.", color: Colors.orange.shade800, maxLines: 3, overflow: TextOverflow.ellipsis, ), ), ], ), ), ); } /// Loading Skeletons Widget _buildLoadingSkeleton(BuildContext context) { return Wrap( spacing: 10, runSpacing: 10, children: List.generate( 4, (index) => _buildStatCardSkeleton(MediaQuery.of(context).size.width / 3), ), ); } /// Skeleton Card Widget _buildStatCardSkeleton(double width) { return MyCard.bordered( width: width, height: 100, paddingAll: 5, borderRadiusAll: 10, border: Border.all(color: Colors.grey.withOpacity(0.15)), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ MyContainer.rounded( paddingAll: 12, color: Colors.grey.shade300, child: const SizedBox(width: 18, height: 18), ), MySpacing.height(8), Container( height: 12, width: 60, color: Colors.grey.shade300, ), ], ), ); } /// Stat Card Widget _buildStatCard(_StatItem statItem, double width, bool isEnabled) { return Opacity( opacity: isEnabled ? 1.0 : 0.4, child: IgnorePointer( ignoring: !isEnabled, child: InkWell( onTap: () => _handleStatCardTap(statItem, isEnabled), borderRadius: BorderRadius.circular(10), child: MyCard.bordered( width: width, height: 100, paddingAll: 5, borderRadiusAll: 10, border: Border.all(color: Colors.grey.withOpacity(0.15)), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _buildStatCardIcon(statItem), MySpacing.height(8), MyText.labelSmall( statItem.title, maxLines: 2, overflow: TextOverflow.visible, textAlign: TextAlign.center, ), ], ), ), ), ), ); } /// Handle Tap void _handleStatCardTap(_StatItem statItem, bool isEnabled) { if (!isEnabled) { Get.defaultDialog( title: "No Project Selected", middleText: "You need to select a project before accessing this section.", confirm: ElevatedButton( onPressed: () => Get.back(), child: const Text("OK"), ), ); } else { Get.toNamed(statItem.route); } } /// Stat Icon Widget _buildStatCardIcon(_StatItem statItem) { return MyContainer.rounded( paddingAll: 10, color: statItem.color.withOpacity(0.1), child: Icon(statItem.icon, size: 18, color: statItem.color), ); } } class _StatItem { final IconData icon; final String title; final Color color; final String route; _StatItem(this.icon, this.title, this.color, this.route); }