import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import '../../providers/auth_provider.dart'; import '../features/cart_page.dart'; import '../features/activity_page.dart'; import '../features/chat_page.dart'; import '../features/profile_page.dart'; import '../features/food_detail_page.dart'; import '../features/kantin_page.dart'; import '../features/makanan_page.dart'; import '../features/minuman_page.dart'; import '../features/snack_page.dart'; class UserDashboard extends StatefulWidget { const UserDashboard({super.key}); @override State createState() => _UserDashboardState(); } class _UserDashboardState extends State { final TextEditingController _searchController = TextEditingController(); final List _pages = [ _HomePage(), const ActivityPage(), const ChatPage(), const ProfilePage(), ]; @override void dispose() { _searchController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final selectedIndex = context.watch().selectedIndex; return Scaffold( body: _pages[selectedIndex], bottomNavigationBar: Container( decoration: BoxDecoration( color: Colors.white, border: Border( top: BorderSide( color: Colors.grey.withOpacity(0.2), width: 1, ), ), ), child: BottomNavigationBar( currentIndex: selectedIndex, onTap: (index) { context.read().setSelectedIndex(index); }, type: BottomNavigationBarType.fixed, backgroundColor: Colors.white, selectedItemColor: Colors.blue, unselectedItemColor: Colors.grey, selectedFontSize: 12, unselectedFontSize: 12, selectedLabelStyle: const TextStyle( fontWeight: FontWeight.normal, height: 1.5, ), unselectedLabelStyle: const TextStyle( fontWeight: FontWeight.normal, height: 1.5, ), elevation: 0, items: [ BottomNavigationBarItem( icon: Padding( padding: const EdgeInsets.only(bottom: 4), child: Icon( Icons.home_outlined, size: 24, color: selectedIndex == 0 ? Colors.blue : Colors.grey, ), ), label: 'Beranda', ), BottomNavigationBarItem( icon: Padding( padding: const EdgeInsets.only(bottom: 4), child: Icon( Icons.article_outlined, size: 24, color: selectedIndex == 1 ? Colors.blue : Colors.grey, ), ), label: 'Aktifitas', ), BottomNavigationBarItem( icon: Padding( padding: const EdgeInsets.only(bottom: 4), child: Icon( Icons.chat_bubble_outline, size: 24, color: selectedIndex == 2 ? Colors.blue : Colors.grey, ), ), label: 'Chat', ), BottomNavigationBarItem( icon: Padding( padding: const EdgeInsets.only(bottom: 4), child: Icon( Icons.person_outline, size: 24, color: selectedIndex == 3 ? Colors.blue : Colors.grey, ), ), label: 'Profil', ), ], ), ), ); } } class _HomePage extends StatelessWidget { final TextEditingController _searchController = TextEditingController(); _HomePage({super.key}); Widget _buildCategoryItem(IconData icon, String label, {VoidCallback? onTap}) { return Column( children: [ GestureDetector( onTap: onTap, child: Container( width: 60, height: 60, margin: const EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(30), ), child: Icon(icon, color: Colors.white), ), ), const SizedBox(height: 4), Text( label, style: const TextStyle( fontSize: 12, color: Colors.black87, ), ), ], ); } Widget _buildMenuItem(BuildContext context) { return GestureDetector( onTap: () { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => const FoodDetailPage( name: 'Nasi Ayam Geprek', description: 'Nasi + ayam geprek + timun + tahu + tempe + sambal bawang', price: 'Rp 10.000', imageUrl: 'assets/images/nasi_ayam.jpg', location: 'Kantin 1', ), ); }, child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), spreadRadius: 1, blurRadius: 4, ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ClipRRect( borderRadius: const BorderRadius.vertical(top: Radius.circular(12)), child: Image.asset( 'assets/images/nasi_ayam.jpg', height: 120, width: double.infinity, fit: BoxFit.cover, ), ), Padding( padding: const EdgeInsets.all(8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Nasi Ayam Geprek', style: TextStyle( fontWeight: FontWeight.w500, fontSize: 14, ), ), const SizedBox(height: 4), const Text( 'Rp 10.000', style: TextStyle( color: Colors.blue, fontWeight: FontWeight.bold, fontSize: 14, ), ), const SizedBox(height: 8), GestureDetector( onTap: () { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => const FoodDetailPage( name: 'Nasi Ayam Geprek', description: 'Nasi + ayam geprek + timun + tahu + tempe + sambal bawang', price: 'Rp 10.000', imageUrl: 'assets/images/nasi_ayam.jpg', location: 'Kantin 1', ), ); }, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(20), ), child: const Text( 'Tambah', style: TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500, ), ), ), ), ], ), ), ], ), ), ); } @override Widget build(BuildContext context) { return SafeArea( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header with Logo and Cart Padding( padding: const EdgeInsets.all(16.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Image.asset( 'assets/images/logo.jpg', height: 30, ), IconButton( icon: const Icon(Icons.shopping_cart_outlined), onPressed: () { showModalBottomSheet( context: context, builder: (context) => const CartPage(), isScrollControlled: true, ); }, ), ], ), ), // Balance Card Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), spreadRadius: 1, blurRadius: 4, ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Saldo Polije Pay', style: TextStyle( color: Colors.grey, fontSize: 12, ), ), const SizedBox(height: 4), Row( children: [ const Icon( Icons.account_balance_wallet, color: Colors.blue, size: 20, ), const SizedBox(width: 8), const Text( 'Rp 25.000', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const Spacer(), Row( children: [ Column( children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.add, color: Colors.white, size: 18, ), ), const SizedBox(height: 2), const Text( 'Bayar', style: TextStyle( fontSize: 10, color: Colors.grey, ), ), ], ), const SizedBox(width: 16), Column( children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.arrow_upward, color: Colors.white, size: 18, ), ), const SizedBox(height: 2), const Text( 'Top Up', style: TextStyle( fontSize: 10, color: Colors.grey, ), ), ], ), const SizedBox(width: 16), Column( children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.more_horiz, color: Colors.white, size: 18, ), ), const SizedBox(height: 2), const Text( 'Lainnya', style: TextStyle( fontSize: 10, color: Colors.grey, ), ), ], ), ], ), ], ), ], ), ), ), const SizedBox(height: 16), // Search Bar Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: TextField( controller: _searchController, decoration: InputDecoration( hintText: 'Mau makan apa hari ini?', hintStyle: TextStyle(color: Colors.grey[400], fontSize: 14), prefixIcon: const Icon(Icons.search, color: Colors.grey), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), filled: true, fillColor: Colors.grey[100], contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), ), ), const SizedBox(height: 20), // Category Icons SizedBox( height: 90, child: ListView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 12), children: [ _buildCategoryItem( Icons.store_outlined, 'Kantin', onTap: () { Navigator.push( context, PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => const KantinPage(), transitionsBuilder: (context, animation, secondaryAnimation, child) { final scale = Tween(begin: 0.8, end: 1.0).animate( CurvedAnimation(parent: animation, curve: Curves.easeOutBack), ); return ScaleTransition( scale: scale, child: child, ); }, transitionDuration: const Duration(milliseconds: 350), reverseTransitionDuration: const Duration(milliseconds: 250), ), ); }, ), _buildCategoryItem( Icons.restaurant_outlined, 'Makanan', onTap: () { Navigator.push( context, PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => const MakananPage(), transitionsBuilder: (context, animation, secondaryAnimation, child) { final scale = Tween(begin: 0.8, end: 1.0).animate( CurvedAnimation(parent: animation, curve: Curves.easeOutBack), ); return ScaleTransition( scale: scale, child: child, ); }, transitionDuration: const Duration(milliseconds: 350), reverseTransitionDuration: const Duration(milliseconds: 250), ), ); }, ), _buildCategoryItem( Icons.local_drink_outlined, 'Minuman', onTap: () { Navigator.push( context, PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => const MinumanPage(), transitionsBuilder: (context, animation, secondaryAnimation, child) { final scale = Tween(begin: 0.8, end: 1.0).animate( CurvedAnimation(parent: animation, curve: Curves.easeOutBack), ); return ScaleTransition( scale: scale, child: child, ); }, transitionDuration: const Duration(milliseconds: 350), reverseTransitionDuration: const Duration(milliseconds: 250), ), ); }, ), _buildCategoryItem( Icons.lunch_dining_outlined, 'Snack', onTap: () { Navigator.push( context, PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => const SnackPage(), transitionsBuilder: (context, animation, secondaryAnimation, child) { final scale = Tween(begin: 0.8, end: 1.0).animate( CurvedAnimation(parent: animation, curve: Curves.easeOutBack), ); return ScaleTransition( scale: scale, child: child, ); }, transitionDuration: const Duration(milliseconds: 350), reverseTransitionDuration: const Duration(milliseconds: 250), ), ); }, ), _buildCategoryItem(Icons.grid_view, 'Semua'), ], ), ), const SizedBox(height: 20), // Banner Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: ClipRRect( borderRadius: BorderRadius.circular(12), child: Image.asset( 'assets/images/banner.jpg', height: 120, width: double.infinity, fit: BoxFit.cover, ), ), ), const SizedBox(height: 20), // Recommended Menu Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Rekomendasi Menu', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), TextButton( onPressed: () { context.push('/sort'); }, style: TextButton.styleFrom( padding: EdgeInsets.zero, minimumSize: Size.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), child: const Text( 'Lihat Semua', style: TextStyle( color: Colors.blue, fontSize: 14, ), ), ), ], ), ), const SizedBox(height: 12), // Menu Grid Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 0.75, crossAxisSpacing: 12, mainAxisSpacing: 12, ), itemCount: 4, itemBuilder: (context, index) { return _buildMenuItem(context); }, ), ), const SizedBox(height: 16), ], ), ), ); } }