import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:get/get.dart'; import 'package:on_field_work/controller/dashboard/dashboard_controller.dart'; import 'package:on_field_work/controller/project_controller.dart'; import 'package:on_field_work/controller/dynamicMenu/dynamic_menu_controller.dart'; import 'package:on_field_work/helpers/services/storage/local_storage.dart'; import 'package:on_field_work/helpers/utils/mixins/ui_mixin.dart'; import 'package:on_field_work/helpers/widgets/my_spacing.dart'; import 'package:on_field_work/helpers/widgets/dashbaord/expense_breakdown_chart.dart'; import 'package:on_field_work/helpers/widgets/dashbaord/expense_by_status_widget.dart'; import 'package:on_field_work/helpers/widgets/dashbaord/monthly_expense_dashboard_chart.dart'; import 'package:on_field_work/view/layouts/layout.dart'; import 'package:on_field_work/helpers/utils/permission_constants.dart'; import 'package:on_field_work/helpers/widgets/my_custom_skeleton.dart '; class DashboardScreen extends StatefulWidget { const DashboardScreen({super.key}); @override State createState() => _DashboardScreenState(); } class _DashboardScreenState extends State with UIMixin { final DashboardController dashboardController = Get.put(DashboardController(), permanent: true); final DynamicMenuController menuController = Get.put(DynamicMenuController()); final ProjectController projectController = Get.find(); bool hasMpin = true; @override void initState() { super.initState(); _checkMpinStatus(); } Future _checkMpinStatus() async { hasMpin = await LocalStorage.getIsMpin(); if (mounted) setState(() {}); } //--------------------------------------------------------------------------- // REUSABLE CARD (smaller, minimal) //--------------------------------------------------------------------------- Widget _cardWrapper({required Widget child}) { return Container( margin: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black12.withOpacity(.04)), boxShadow: [ BoxShadow( color: Colors.black12.withOpacity(.05), blurRadius: 12, offset: const Offset(0, 4), ) ], ), child: child, ); } //--------------------------------------------------------------------------- // SECTION TITLE //--------------------------------------------------------------------------- Widget _sectionTitle(String title) { return Padding( padding: const EdgeInsets.only(left: 4, bottom: 8), child: Text( title, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w700, color: Colors.black87, ), ), ); } Widget _conditionalQuickActionCard() { String status = "1"; // <-- change as needed bool isCheckedIn = status == "O"; // Button color remains the same Color buttonColor = isCheckedIn ? Colors.red.shade700 : Colors.green.shade700; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), gradient: LinearGradient( colors: [ contentTheme.primary.withOpacity(0.3), // lighter/faded contentTheme.primary.withOpacity(0.6), // slightly stronger ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: Colors.black12.withOpacity(0.05), blurRadius: 6, offset: const Offset(0, 3), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title & Status Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( isCheckedIn ? "Checked-In" : "Not Checked-In", style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white, ), ), Icon( isCheckedIn ? LucideIcons.log_out : LucideIcons.log_in, color: Colors.white, size: 24, ), ], ), const SizedBox(height: 8), // Description Text( isCheckedIn ? "You are currently checked-in. Don't forget to check-out after your work." : "You are not checked-in yet. Please check-in to start your work.", style: const TextStyle(color: Colors.white70, fontSize: 13), ), const SizedBox(height: 12), // Action Button (solid color) Row( mainAxisAlignment: MainAxisAlignment.end, children: [ ElevatedButton.icon( onPressed: () { // Check-In / Check-Out action }, icon: Icon( isCheckedIn ? LucideIcons.log_out : LucideIcons.log_in, size: 16, ), label: Text(isCheckedIn ? "Check-Out" : "Check-In"), style: ElevatedButton.styleFrom( backgroundColor: buttonColor, foregroundColor: Colors.white, ), ), ], ), ], ), ); } //--------------------------------------------------------------------------- // QUICK ACTIONS (updated to use the single card) //--------------------------------------------------------------------------- Widget _quickActions() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _sectionTitle("Quick Action"), _conditionalQuickActionCard(), ], ); } //--------------------------------------------------------------------------- // PROJECT DROPDOWN (clean compact) //--------------------------------------------------------------------------- Widget _projectSelector() { return Obx(() { final isLoading = projectController.isLoading.value; final expanded = projectController.isProjectSelectionExpanded.value; final projects = projectController.projects; final selectedId = projectController.selectedProjectId.value; if (isLoading) { // Use skeleton instead of CircularProgressIndicator return SkeletonLoaders.dashboardCardsSkeleton( maxWidth: MediaQuery.of(context).size.width); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _sectionTitle("Project"), // Compact Selector GestureDetector( onTap: () => projectController.isProjectSelectionExpanded.toggle(), child: Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black12.withOpacity(.15)), boxShadow: [ BoxShadow( color: Colors.black12.withOpacity(.04), blurRadius: 6, offset: const Offset(0, 2), ) ], ), child: Row( children: [ const Icon(Icons.work_outline, color: Colors.blue, size: 20), const SizedBox(width: 12), Expanded( child: Text( projects .firstWhereOrNull((p) => p.id == selectedId) ?.name ?? "Select Project", style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w600), ), ), Icon( expanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, size: 26, color: Colors.black54, ) ], ), ), ), if (expanded) _projectDropdownList(projects, selectedId), ], ); }); } //--------------------------------------------------------------------------- // DASHBOARD MODULE CARDS (UPDATED FOR MINIMAL PADDING / SLL SIZE) //--------------------------------------------------------------------------- Widget _dashboardCards() { return Obx(() { if (menuController.isLoading.value) { // Show skeleton instead of CircularProgressIndicator return SkeletonLoaders.dashboardCardsSkeleton( maxWidth: MediaQuery.of(context).size.width); } final projectSelected = projectController.selectedProject != null; final cardOrder = [ MenuItems.attendance, MenuItems.employees, MenuItems.dailyTaskPlanning, MenuItems.dailyProgressReport, MenuItems.directory, MenuItems.finance, MenuItems.documents, MenuItems.serviceProjects, ]; final meta = { MenuItems.attendance: _DashboardCardMeta(LucideIcons.scan_face, contentTheme.success), MenuItems.employees: _DashboardCardMeta(LucideIcons.users, contentTheme.warning), MenuItems.dailyTaskPlanning: _DashboardCardMeta(LucideIcons.logs, contentTheme.info), MenuItems.dailyProgressReport: _DashboardCardMeta(LucideIcons.list_todo, contentTheme.info), MenuItems.directory: _DashboardCardMeta(LucideIcons.folder, contentTheme.info), MenuItems.finance: _DashboardCardMeta(LucideIcons.wallet, contentTheme.info), MenuItems.documents: _DashboardCardMeta(LucideIcons.file_text, contentTheme.info), MenuItems.serviceProjects: _DashboardCardMeta(LucideIcons.package, contentTheme.info), }; final allowed = { for (var m in menuController.menuItems) if (m.available && meta.containsKey(m.id)) m.id: m }; final filtered = cardOrder.where(allowed.containsKey).toList(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _sectionTitle("Modules"), GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), // **More compact grid** gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, crossAxisSpacing: 6, mainAxisSpacing: 6, childAspectRatio: 1.2, // smaller & tighter ), itemCount: filtered.length, itemBuilder: (context, index) { final id = filtered[index]; final item = allowed[id]!; final cardMeta = meta[id]!; final isEnabled = item.name == "Attendance" ? true : projectSelected; return GestureDetector( onTap: () { if (!isEnabled) { Get.defaultDialog( title: "No Project Selected", middleText: "Please select a project first.", ); } else { Get.toNamed(item.mobileLink); } }, child: Container( // **Reduced padding** padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: isEnabled ? Colors.white : Colors.grey.shade100, borderRadius: BorderRadius.circular(5), border: Border.all( color: Colors.black12.withOpacity(.1), width: 0.7, ), boxShadow: [ BoxShadow( color: Colors.black12.withOpacity(.05), blurRadius: 4, offset: const Offset(0, 2), ) ], ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( cardMeta.icon, size: 20, color: isEnabled ? cardMeta.color : Colors.grey.shade400, ), const SizedBox(height: 3), Text( item.name, textAlign: TextAlign.center, style: TextStyle( fontSize: 9.5, fontWeight: FontWeight.w600, color: isEnabled ? Colors.black87 : Colors.grey.shade600, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), ); }, ), ], ); }); } Widget _projectDropdownList(projects, selectedId) { return Container( margin: const EdgeInsets.only(top: 10), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black12.withOpacity(.2)), boxShadow: [ BoxShadow( color: Colors.black12.withOpacity(.07), blurRadius: 10, offset: const Offset(0, 3), ), ], ), constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.33), child: Column( children: [ TextField( decoration: InputDecoration( hintText: "Search project...", isDense: true, prefixIcon: const Icon(Icons.search), border: OutlineInputBorder(borderRadius: BorderRadius.circular(5)), ), ), const SizedBox(height: 10), Expanded( child: ListView.builder( itemCount: projects.length, itemBuilder: (_, index) { final project = projects[index]; return RadioListTile( dense: true, value: project.id, groupValue: selectedId, onChanged: (v) { if (v != null) { projectController.updateSelectedProject(v); projectController.isProjectSelectionExpanded.value = false; } }, title: Text(project.name), ); }, ), ), ], ), ); } //--------------------------------------------------------------------------- // MAIN UI //--------------------------------------------------------------------------- @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xfff5f6fa), body: Layout( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _projectSelector(), MySpacing.height(20), _quickActions(), MySpacing.height(20), // The updated module cards _dashboardCards(), MySpacing.height(20), _sectionTitle("Reports & Analytics"), _cardWrapper(child: ExpenseTypeReportChart()), _cardWrapper( child: ExpenseByStatusWidget(controller: dashboardController)), _cardWrapper(child: MonthlyExpenseDashboardChart()), MySpacing.height(20), ], ), ), ), ); } } class _DashboardCardMeta { final IconData icon; final Color color; _DashboardCardMeta(this.icon, this.color); }