import 'package:flutter/material.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:tugas_akhir_supabase/core/theme/app_colors.dart'; import 'package:tugas_akhir_supabase/screens/admin/user_management.dart'; import 'package:tugas_akhir_supabase/screens/admin/guide_management.dart'; import 'package:tugas_akhir_supabase/screens/admin/crop_management.dart'; import 'package:tugas_akhir_supabase/screens/admin/community_management.dart'; import 'package:tugas_akhir_supabase/screens/admin/news_management.dart'; import 'package:tugas_akhir_supabase/services/auth_services.dart'; import 'package:tugas_akhir_supabase/services/user_presence_service.dart'; import 'package:get_it/get_it.dart'; import 'package:intl/intl.dart'; import 'dart:ui' as ui; class AdminDashboard extends StatefulWidget { const AdminDashboard({super.key}); @override State createState() => _AdminDashboardState(); } class _AdminDashboardState extends State { final _authServices = GetIt.instance(); UserPresenceService? _presenceService; bool _isLoading = true; bool _isAdmin = false; int _currentIndex = 0; // Statistik dashboard int _totalUsers = 0; int _activeUsers = 0; int _totalPosts = 0; int _totalGuides = 0; int _totalNews = 0; final int _totalCrops = 0; // Statistik tambahan final int _newUsersToday = 0; final int _newPostsToday = 0; final List> _recentActivities = []; // Real-time active users int _realtimeActiveUsers = 0; final Map> _onlineUsers = {}; // Status sistem final bool _systemStatus = true; String _lastUpdated = ''; // Professional Color Scheme static const Color primaryGreen = Color(0xFF0F6848); static const Color lightGreen = Color(0xFF4CAF50); static const Color accentGreen = Color(0xFF66BB6A); static const Color surfaceGreen = Color(0xFFEDF7ED); static const Color bgWhite = Color(0xFFF8F9FA); static const Color cardWhite = Colors.white; static const Color textPrimary = Color(0xFF1E293B); static const Color textSecondary = Color(0xFF64748B); static const Color dividerColor = Color(0xFFE2E8F0); static const Color accentBlue = Color(0xFF2563EB); static const Color accentOrange = Color(0xFFEA580C); static const Color chartGreen = Color(0xFF10B981); static const Color chartBlue = Color(0xFF3B82F6); static const Color chartOrange = Color(0xFFF97316); static const Color chartPurple = Color(0xFF8B5CF6); @override void initState() { super.initState(); // Safely initialize the presence service try { if (GetIt.instance.isRegistered()) { _presenceService = GetIt.instance(); // Listen to online users count updates _presenceService?.onlineUsersStream.listen((count) { if (mounted) { setState(() { // Update the active users count _activeUsers = count; _realtimeActiveUsers = count; }); } }); } else { debugPrint('UserPresenceService is not registered in GetIt'); // Register the service if needed final currentUser = Supabase.instance.client.auth.currentUser; if (currentUser != null) { debugPrint('Registering UserPresenceService for admin dashboard'); GetIt.instance.registerSingleton( UserPresenceService(), ); _presenceService = GetIt.instance(); _presenceService?.initialize().then((_) { _presenceService?.onlineUsersStream.listen((count) { if (mounted) { setState(() { _activeUsers = count; _realtimeActiveUsers = count; }); } }); }); } } } catch (e) { debugPrint('Error initializing UserPresenceService: $e'); } _checkAdminAccess(); _loadDashboardStats(); // Tambahkan refresh otomatis setelah beberapa detik // untuk memastikan data terambil dengan benar Future.delayed(const Duration(seconds: 2), () { if (mounted) { _refreshDashboardData(); } }); } @override void dispose() { super.dispose(); } // Load dashboard statistics from Supabase Future _loadDashboardStats() async { if (!mounted) return; if (mounted) { setState(() => _isLoading = true); } try { debugPrint('🔍 Starting to load dashboard stats...'); final now = DateTime.now(); final formatter = DateFormat('dd MMM yyyy HH:mm'); final client = Supabase.instance.client; // Fetch user count using the same approach as UserManagement try { debugPrint('🔍 Attempting to fetch users with get_all_users RPC...'); // Try to execute the get_all_users function final response = await client.rpc('get_all_users'); debugPrint('🔍 get_all_users response type: ${response.runtimeType}'); debugPrint('🔍 get_all_users response length: ${response.length}'); debugPrint('🔍 get_all_users response: $response'); // Handle different response types int userCount = 0; if (response is List) { userCount = response.length; debugPrint('✅ Parsed ${userCount} users from List response'); } else if (response is Map) { userCount = 1; debugPrint('✅ Parsed 1 user from Map response'); } else { debugPrint('⚠️ Unknown response type, trying to convert...'); try { final users = List>.from(response); userCount = users.length; debugPrint('✅ Converted to ${userCount} users'); } catch (e) { debugPrint('❌ Failed to convert response: $e'); // Try to get length directly try { final length = response.length; userCount = length ?? 0; debugPrint('✅ Got length directly: $userCount'); } catch (e2) { debugPrint('❌ Failed to get length directly: $e2'); userCount = 0; } } } if (mounted) { setState(() { _totalUsers = userCount; debugPrint('✅ Set _totalUsers to $userCount'); debugPrint( '🔍 User count verification: userCount=$userCount, _totalUsers=$_totalUsers', ); }); debugPrint('✅ setState called for userCount: $userCount'); // Verify the value was set debugPrint( '✅ Verification: _totalUsers after setState = $_totalUsers', ); } else { debugPrint('❌ Widget not mounted, cannot setState'); } } catch (e) { debugPrint('❌ Error fetching users with get_all_users: $e'); // Fallback to manual query if the RPC fails try { debugPrint('🔍 Falling back to manual profiles query...'); // Directly fetch all users from profiles table final profilesResponse = await client .from('profiles') .select('*') .order('created_at', ascending: false); debugPrint('🔍 Profiles loaded: ${profilesResponse.length}'); // Convert to List final profiles = List>.from(profilesResponse); if (mounted) { setState(() { _totalUsers = profiles.length; debugPrint( '✅ Fetched ${profiles.length} users from profiles table', ); }); } } catch (fallbackError) { debugPrint('❌ Even fallback query failed: $fallbackError'); // Set a default value to prevent issues if (mounted) { setState(() { _totalUsers = 0; }); } } } debugPrint( '📊 Current stats after user fetch: Users: $_totalUsers, Active: $_activeUsers', ); // Fetch guides count try { debugPrint('🔍 Fetching guides...'); final guidesResponse = await client.from('farming_guides').select(); if (mounted) { setState(() { _totalGuides = guidesResponse.length; debugPrint('✅ Fetched ${guidesResponse.length} guides'); }); } } catch (e) { debugPrint('❌ Error fetching guides count: $e'); if (mounted) { setState(() { _totalGuides = 0; }); } } debugPrint( '📊 Current stats: Users: $_totalUsers, Guides: $_totalGuides', ); // Fetch news count try { final newsResponse = await client.from('saved_news').select(); if (mounted) { setState(() { _totalNews = newsResponse.length; debugPrint('Fetched ${newsResponse.length} news articles'); }); } } catch (e) { debugPrint('Error fetching news count: $e'); if (mounted) { setState(() { _totalNews = 0; }); } } // Fetch community messages count try { final postsResponse = await client.from('community_messages').select(); if (mounted) { setState(() { _totalPosts = postsResponse.length; debugPrint('Fetched ${postsResponse.length} community posts'); }); } } catch (e) { debugPrint('Error fetching community posts count: $e'); if (mounted) { setState(() { _totalPosts = 0; }); } } if (mounted) { setState(() { _isLoading = false; _lastUpdated = formatter.format(now); debugPrint('🕒 Last updated: $_lastUpdated'); debugPrint( '📊 FINAL STATS: Users: $_totalUsers, Active: $_activeUsers, Guides: $_totalGuides, News: $_totalNews, Posts: $_totalPosts', ); }); } } catch (e) { debugPrint('❌ Error loading dashboard stats: $e'); if (mounted) { setState(() => _isLoading = false); } } } Future _checkAdminAccess() async { debugPrint('DEBUG: Mulai cek akses admin...'); if (mounted) { setState(() => _isLoading = true); } try { final isAdmin = await _authServices.isAdmin(); debugPrint('DEBUG: Hasil cek isAdmin: $isAdmin'); if (mounted) { setState(() { _isAdmin = isAdmin; _isLoading = false; }); } // Only kick out if definitely not admin and we're sure about it if (isAdmin == false) { debugPrint('DEBUG: User bukan admin, akan pop dan tampilkan snackbar'); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text( 'Access denied. Admin privileges required.', ), backgroundColor: Colors.red.shade400, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ); } }); } else { debugPrint('DEBUG: User adalah admin, melanjutkan...'); } } catch (e) { debugPrint('DEBUG: Error checking admin access: $e'); // Don't kick out on error, just show error message if (mounted) { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Error checking admin access: ${e.toString()}'), backgroundColor: Colors.orange.shade400, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ); } } debugPrint('DEBUG: Selesai cek akses admin.'); } Future _refreshDashboardData() async { if (mounted) { debugPrint('🔄 Refreshing dashboard data...'); await _loadDashboardStats(); // Update active users count try { if (_presenceService != null) { debugPrint('🔄 Fetching online users from presence service...'); final onlineUsers = await _presenceService!.getOnlineUsers(); if (mounted) { setState(() { _activeUsers = onlineUsers.length; _realtimeActiveUsers = onlineUsers.length; debugPrint('🔄 Updated active users count: $_activeUsers'); }); } } else { // Try to get the service if it was registered after initialization try { if (GetIt.instance.isRegistered()) { debugPrint('🔄 Getting UserPresenceService from GetIt...'); _presenceService = GetIt.instance(); final onlineUsers = await _presenceService!.getOnlineUsers(); if (mounted) { setState(() { _activeUsers = onlineUsers.length; _realtimeActiveUsers = onlineUsers.length; debugPrint('🔄 Updated active users count: $_activeUsers'); }); } } else { debugPrint('⚠️ UserPresenceService not registered in GetIt'); } } catch (e) { debugPrint('❌ Error getting UserPresenceService: $e'); } } } catch (e) { debugPrint('❌ Error getting online users: $e'); } debugPrint( '🔄 Refresh complete. Users: $_totalUsers, Active: $_activeUsers', ); } } Widget _buildStatsGrid() { return GridView.count( crossAxisCount: 2, childAspectRatio: 1.2, padding: const EdgeInsets.all(4), mainAxisSpacing: 12, crossAxisSpacing: 12, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), children: [ _buildStatCard( title: 'Total Pengguna', value: '$_totalUsers', subtitle: '+$_newUsersToday today', icon: Icons.people, color: chartBlue, ), _buildActiveUsersCard(), _buildStatCard( title: 'News', value: '$_totalNews', subtitle: 'Saved articles', icon: Icons.newspaper, color: chartPurple, ), _buildStatCard( title: 'Panduan', value: '$_totalGuides', subtitle: 'Published guides', icon: Icons.book, color: chartOrange, ), ], ); } Widget _buildActiveUsersCard() { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: chartGreen.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon(Icons.people, color: chartGreen, size: 16), ), const SizedBox(height: 8), Text( '$_realtimeActiveUsers', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: textPrimary, ), overflow: TextOverflow.ellipsis, ), const SizedBox(height: 2), Text( 'Pengguna Aktif', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: textSecondary, ), overflow: TextOverflow.ellipsis, ), const SizedBox(height: 2), Text( 'Online saat ini', style: TextStyle( fontSize: 10, color: chartGreen.withOpacity(0.8), fontWeight: FontWeight.w500, ), overflow: TextOverflow.ellipsis, ), ], ), ); } Widget _buildStatCard({ required String title, required String value, required String subtitle, required IconData icon, required Color color, }) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon(icon, color: color, size: 16), ), const SizedBox(height: 8), Text( value, style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: textPrimary, ), overflow: TextOverflow.ellipsis, ), const SizedBox(height: 2), Text( title, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: textSecondary, ), overflow: TextOverflow.ellipsis, ), const SizedBox(height: 2), Text( subtitle, style: TextStyle( fontSize: 10, color: color.withOpacity(0.8), fontWeight: FontWeight.w500, ), overflow: TextOverflow.ellipsis, ), ], ), ); } @override Widget build(BuildContext context) { try { debugPrint('DEBUG: build() AdminDashboard dipanggil'); // Define page content based on selected index Widget pageContent; switch (_currentIndex) { case 0: pageContent = _buildOverviewTab(); break; case 1: pageContent = const UserManagement(); break; case 2: pageContent = const GuideManagement(); break; // case 3: // Removing Crops tab from admin // pageContent = const CropManagement(); // break; case 3: // Updated index after removing Crops pageContent = const CommunityManagement(); break; case 4: // Updated index after removing Crops pageContent = const NewsManagement(); break; default: pageContent = _buildOverviewTab(); } return Scaffold( backgroundColor: const Color(0xFFF5F7FA), appBar: AppBar( title: const Text( 'Admin Dashboard', style: TextStyle(fontWeight: FontWeight.w600), ), centerTitle: true, backgroundColor: AppColors.primary, foregroundColor: Colors.white, elevation: 2, actions: [ IconButton( icon: const Icon(Icons.exit_to_app), onPressed: () { Navigator.pop(context); }, ), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : !_isAdmin ? const Center( child: Text('Access denied. Admin privileges required.'), ) : pageContent, bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, onTap: (index) { setState(() { _currentIndex = index; }); }, type: BottomNavigationBarType.fixed, backgroundColor: Colors.white, selectedItemColor: AppColors.primary, unselectedItemColor: Colors.grey, selectedFontSize: 12, unselectedFontSize: 12, items: const [ BottomNavigationBarItem( icon: Icon(Icons.dashboard_outlined), activeIcon: Icon(Icons.dashboard), label: 'Overview', ), BottomNavigationBarItem( icon: Icon(Icons.people_outline), activeIcon: Icon(Icons.people), label: 'Users', ), BottomNavigationBarItem( icon: Icon(Icons.book_outlined), activeIcon: Icon(Icons.book), label: 'Guides', ), // BottomNavigationBarItem( // icon: Icon(Icons.agriculture_outlined), // activeIcon: Icon(Icons.agriculture), // label: 'Crops', // ), BottomNavigationBarItem( icon: Icon(Icons.forum_outlined), activeIcon: Icon(Icons.forum), label: 'Community', ), BottomNavigationBarItem( icon: Icon(Icons.newspaper_outlined), activeIcon: Icon(Icons.newspaper), label: 'News', ), ], ), ); } catch (e, stack) { debugPrint('DEBUG: Exception di build AdminDashboard: $e\n$stack'); return Center(child: Text('Error: $e')); } } Widget _buildOverviewTab() { return RefreshIndicator( onRefresh: _refreshDashboardData, color: primaryGreen, child: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Section _buildHeaderSection(), const SizedBox(height: 20), // Main Statistics Grid _buildMainStatsGrid(), const SizedBox(height: 24), // Quick Actions Section _buildQuickActionsSection(), const SizedBox(height: 24), ], ), ), ); } Widget _buildHeaderSection() { final now = DateTime.now(); final greeting = now.hour < 12 ? 'Good Morning' : now.hour < 17 ? 'Good Afternoon' : 'Good Evening'; return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( gradient: LinearGradient( colors: [ const Color(0xFF0F172A), // Slate-900 const Color(0xFF1E293B), // Slate-800 ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: const Color(0xFF0F172A).withOpacity(0.2), blurRadius: 12, offset: const Offset(0, 4), spreadRadius: -2, ), ], ), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Top row with timestamp and refresh button Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [_buildTimeStamp(), _buildActionButton()], ), const SizedBox(height: 16), // System health card (wider) _buildSystemMetricsWide(), const SizedBox(height: 16), // Greeting text Text( greeting, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xFF10B981), letterSpacing: 0.5, ), ), const SizedBox(height: 4), // Welcome text with glow Container( decoration: BoxDecoration( boxShadow: [ BoxShadow( color: const Color(0xFF10B981).withOpacity(0.2), blurRadius: 10, spreadRadius: 1, ), ], ), child: const Text( 'Welcome to TaniSMART', style: TextStyle( fontSize: 22, fontWeight: FontWeight.w700, color: Colors.white, height: 1.1, letterSpacing: -0.5, ), ), ), const SizedBox(height: 16), // Quick stats row _buildQuickStats(), ], ), ), ); } Widget _buildTimeStamp() { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: Colors.white.withOpacity(0.08), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.white.withOpacity(0.1)), ), child: Text( 'Last updated: $_lastUpdated', style: TextStyle( fontSize: 10, fontWeight: FontWeight.w500, color: Colors.white.withOpacity(0.7), letterSpacing: 0.2, ), ), ); } Widget _buildQuickStats() { return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ _buildStatPill( label: 'Users', value: '$_totalUsers', icon: Icons.people_alt_outlined, color: chartBlue, ), const SizedBox(width: 8), _buildStatPill( label: 'Online', value: '$_realtimeActiveUsers', icon: Icons.online_prediction_outlined, color: chartGreen, ), const SizedBox(width: 8), _buildStatPill( label: 'News', value: '$_totalNews', icon: Icons.newspaper_outlined, color: chartPurple, ), const SizedBox(width: 8), _buildStatPill( label: 'Guides', value: '$_totalGuides', icon: Icons.menu_book_outlined, color: chartOrange, ), ], ), ); } Widget _buildStatPill({ required String label, required String value, required IconData icon, required Color color, }) { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: Colors.white.withOpacity(0.08), borderRadius: BorderRadius.circular(20), border: Border.all(color: Colors.white.withOpacity(0.1)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 12, color: color), const SizedBox(width: 6), Text( '$label: ', style: TextStyle( fontSize: 11, color: Colors.white.withOpacity(0.7), fontWeight: FontWeight.w400, ), ), Text( value, style: const TextStyle( fontSize: 11, color: Colors.white, fontWeight: FontWeight.w600, ), ), ], ), ); } Widget _buildSystemMetricsWide() { return Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: Colors.white.withOpacity(0.05), borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.white.withOpacity(0.1)), ), child: Row( children: [ Container( width: 32, height: 32, decoration: BoxDecoration( color: _systemStatus ? const Color(0xFF10B981).withOpacity(0.2) : const Color(0xFFEF4444).withOpacity(0.2), shape: BoxShape.circle, border: Border.all( color: _systemStatus ? const Color(0xFF10B981).withOpacity(0.4) : const Color(0xFFEF4444).withOpacity(0.4), width: 1, ), ), child: Icon( _systemStatus ? Icons.eco_rounded : Icons.warning_rounded, color: _systemStatus ? const Color(0xFF10B981) : const Color(0xFFEF4444), size: 16, ), ), const SizedBox(width: 12), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( _systemStatus ? '99.8%' : '87.3%', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: Colors.white, letterSpacing: -0.5, ), ), Text( 'System Health', style: TextStyle( fontSize: 11, fontWeight: FontWeight.w500, color: Colors.white.withOpacity(0.7), letterSpacing: 0.3, ), ), ], ), const Spacer(), Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: _systemStatus ? const Color(0xFF10B981).withOpacity(0.2) : const Color(0xFFEF4444).withOpacity(0.2), borderRadius: BorderRadius.circular(8), ), child: Text( _systemStatus ? 'Optimal' : 'Attention', style: TextStyle( fontSize: 11, fontWeight: FontWeight.w600, color: _systemStatus ? const Color(0xFF10B981) : const Color(0xFFEF4444), letterSpacing: 0.5, ), ), ), ], ), ); } Widget _buildActionButton() { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), gradient: const LinearGradient( colors: [Color(0xFF10B981), Color(0xFF059669)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: const Color(0xFF10B981).withOpacity(0.3), blurRadius: 12, offset: const Offset(0, 4), ), ], ), child: Material( color: Colors.transparent, child: InkWell( onTap: _refreshDashboardData, borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.refresh_rounded, color: Colors.white, size: 16, ), const SizedBox(width: 3), const Text( 'Refresh Data', style: TextStyle( fontSize: 8, fontWeight: FontWeight.w600, color: Colors.white, letterSpacing: 0.3, ), ), ], ), ), ), ), ); } Widget _buildMainStatsGrid() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Platform Overview', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: textPrimary, letterSpacing: 0.3, ), ), TextButton.icon( onPressed: _refreshDashboardData, icon: Icon( Icons.analytics_outlined, size: 14, color: accentBlue, ), label: Text( 'View Analytics', style: TextStyle( fontSize: 12, color: accentBlue, fontWeight: FontWeight.w500, ), ), style: TextButton.styleFrom( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), ), ), ], ), ), _buildStatsGrid(), ], ); } Widget _buildQuickActionsSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Quick Actions', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: textPrimary, letterSpacing: 0.3, ), ), ], ), ), Container( decoration: BoxDecoration( color: cardWhite, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 8, offset: const Offset(0, 2), ), ], border: Border.all(color: Colors.grey.shade100), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ _buildQuickActionItem( title: 'Manage Users', subtitle: '$_totalUsers total users, $_activeUsers active', icon: Icons.people_alt_rounded, iconColor: chartBlue, onTap: () => setState(() => _currentIndex = 1), ), Divider(height: 1, color: dividerColor), _buildQuickActionItem( title: 'Manage Guides', subtitle: '$_totalGuides farming guides', icon: Icons.menu_book_rounded, iconColor: chartOrange, onTap: () => setState(() => _currentIndex = 2), ), Divider(height: 1, color: dividerColor), _buildQuickActionItem( title: 'News Management', subtitle: '$_totalNews saved news articles', icon: Icons.newspaper_rounded, iconColor: chartPurple, onTap: () => setState(() => _currentIndex = 4), ), Divider(height: 1, color: dividerColor), _buildQuickActionItem( title: 'Community Management', subtitle: '$_totalPosts posts, +$_newPostsToday today', icon: Icons.forum_rounded, iconColor: chartGreen, onTap: () => setState(() => _currentIndex = 3), ), ], ), ), ], ); } Widget _buildQuickActionItem({ required String title, required String subtitle, required IconData icon, required Color iconColor, required VoidCallback onTap, }) { return InkWell( onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: iconColor.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon(icon, size: 18, color: iconColor), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: textPrimary, ), overflow: TextOverflow.ellipsis, ), const SizedBox(height: 2), Text( subtitle, style: TextStyle(fontSize: 12, color: textSecondary), overflow: TextOverflow.ellipsis, ), ], ), ), Icon(Icons.chevron_right, color: Colors.grey.shade400, size: 18), ], ), ), ); } Widget _buildRecentActivitiesSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(bottom: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Recent Activities', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: textPrimary, letterSpacing: 0.3, ), ), TextButton( onPressed: _refreshDashboardData, style: TextButton.styleFrom( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 8, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Text( 'View All', style: TextStyle( fontSize: 13, color: accentBlue, fontWeight: FontWeight.w500, ), ), ), ], ), ), _buildRecentActivitiesList(), ], ); } Widget _buildRecentActivitiesList() { if (_recentActivities.isEmpty) { return Container( padding: const EdgeInsets.all(32), decoration: BoxDecoration( color: cardWhite, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 8, offset: const Offset(0, 2), ), ], border: Border.all(color: Colors.grey.shade100), ), child: Center( child: Column( children: [ Icon( Icons.inbox_rounded, size: 48, color: textSecondary.withOpacity(0.7), ), const SizedBox(height: 16), Text( 'No recent activities', style: TextStyle( color: textSecondary, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 8), ElevatedButton( onPressed: _refreshDashboardData, style: ElevatedButton.styleFrom( backgroundColor: primaryGreen, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text('Refresh Data'), ), ], ), ), ); } return Container( decoration: BoxDecoration( color: cardWhite, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 8, offset: const Offset(0, 2), ), ], border: Border.all(color: Colors.grey.shade100), ), child: ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: _recentActivities.length, separatorBuilder: (context, index) => Divider(height: 1, color: dividerColor), itemBuilder: (context, index) { final activity = _recentActivities[index]; final username = activity['profiles']?['username'] ?? 'Anonymous User'; final content = activity['content'] ?? ''; final createdAt = activity['created_at'] != null ? DateFormat( 'MMM dd, HH:mm', ).format(DateTime.parse(activity['created_at'])) : ''; // Get avatar URL if available final avatarUrl = activity['profiles']?['avatar_url']; return ListTile( contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, ), leading: Container( width: 44, height: 44, decoration: BoxDecoration( color: chartBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(10), border: Border.all(color: Colors.grey.shade100), ), child: ClipRRect( borderRadius: BorderRadius.circular(10), child: avatarUrl != null && avatarUrl.toString().isNotEmpty ? Image.network( avatarUrl, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) => Icon( Icons.person_rounded, color: chartBlue, size: 22, ), ) : Icon( Icons.person_rounded, color: chartBlue, size: 22, ), ), ), title: Row( children: [ Expanded( child: Text( username, style: TextStyle( fontWeight: FontWeight.w600, color: textPrimary, fontSize: 15, ), ), ), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2, ), decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: BorderRadius.circular(12), ), child: Text( createdAt, style: TextStyle( fontSize: 11, color: textSecondary, fontWeight: FontWeight.w500, ), ), ), ], ), subtitle: Padding( padding: const EdgeInsets.only(top: 6), child: Text( content.length > 100 ? '${content.substring(0, 100)}...' : content, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle(color: textSecondary, fontSize: 13), ), ), ); }, ), ); } }