import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../controllers/warga_dashboard_controller.dart'; import '../views/warga_layout.dart'; import '../../../theme/app_colors.dart'; import '../../../widgets/app_drawer.dart'; import '../../../routes/app_routes.dart'; import 'package:intl/intl.dart'; class WargaDashboardView extends GetView { const WargaDashboardView({super.key}); @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; // Check if coming from login and trigger refresh WidgetsBinding.instance.addPostFrameCallback((_) { final args = Get.arguments; final bool isFromLogin = args != null && args['from_login'] == true; if (isFromLogin) { // Trigger refresh after UI is built controller.refreshData(); print( 'WargaDashboardView: Auto-refreshed data due to login navigation', ); } }); return WillPopScope( onWillPop: () async => false, // Prevent back navigation child: WargaLayout( drawer: AppDrawer( onNavItemTapped: controller.onNavItemTapped, onLogout: controller.logout, ), backgroundColor: AppColors.background, appBar: AppBar( elevation: 0, backgroundColor: AppColors.primary, title: const Text( 'Beranda', style: TextStyle(fontWeight: FontWeight.w600), ), centerTitle: true, ), body: RefreshIndicator( color: AppColors.primary, onRefresh: () async { // Re-fetch data when pulled down await Future.delayed(const Duration(seconds: 1)); controller.refreshData(); }, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildUserGreetingHeader(context), _buildActionButtons(), _buildActiveRentalsSection(context), const SizedBox(height: 24), ], ), ), ), ), ); } // Modern welcome header with user profile Widget _buildUserGreetingHeader(BuildContext context) { return Container( width: double.infinity, decoration: BoxDecoration( color: AppColors.primary, borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(30), bottomRight: Radius.circular(30), ), ), child: SafeArea( child: Padding( padding: const EdgeInsets.fromLTRB(20, 0, 20, 30), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ // User avatar Obx(() { final avatarUrl = controller.userAvatar.value; return Container( height: 60, width: 60, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: Colors.white, width: 2), color: Colors.white.withOpacity(0.2), ), child: ClipRRect( borderRadius: BorderRadius.circular(30), child: avatarUrl != null && avatarUrl.isNotEmpty ? Image.network( avatarUrl, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) => _buildAvatarFallback(), loadingBuilder: (context, child, progress) { if (progress == null) return child; return _buildAvatarFallback(); }, ) : _buildAvatarFallback(), ), ); }), const SizedBox(width: 16), // Greeting and name Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _getGreeting(), style: const TextStyle( fontSize: 15, color: Colors.white70, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 4), Obx( () => Text( controller.userName.value, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), overflow: TextOverflow.ellipsis, ), ), ], ), ), ], ), ], ), ), ), ); } // Action buttons in a horizontal scroll Widget _buildActionButtons() { // Define services - removed Langganan and Pengaduan final services = [ { 'title': 'Aset Tunggal', 'icon': Icons.home_work_outlined, 'color': const Color(0xFF4CAF50), 'route': () => controller.navigateToRentals(), }, { 'title': 'Paket', 'icon': Icons.widgets_outlined, 'color': const Color(0xFF2196F3), 'route': () => controller.toSewaAsetTabPaket(), }, ]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Padding( padding: const EdgeInsets.fromLTRB(20, 10, 20, 10), child: Text( 'Layanan Sewa', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColors.textPrimary, ), ), ), // Service cards in grid GridView.count( crossAxisCount: 2, childAspectRatio: 1.5, physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, padding: const EdgeInsets.symmetric(horizontal: 16), mainAxisSpacing: 16, crossAxisSpacing: 16, children: services .map( (service) => _buildServiceCard( title: service['title'] as String, icon: service['icon'] as IconData, color: service['color'] as Color, onTap: service['route'] as VoidCallback, ), ) .toList(), ), // Activity Summaries Section Padding( padding: const EdgeInsets.fromLTRB(20, 24, 20, 10), child: Text( 'Ringkasan Aktivitas', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColors.textPrimary, ), ), ), // Summary Cards Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( children: [ // Sewa Diterima Obx( () => _buildActivityCard( title: 'Sewa Diterima', value: controller.diterimaCount.value.toString(), icon: Icons.check_circle_outline, color: AppColors.success, onTap: () => Get.toNamed(Routes.WARGA_SEWA, arguments: {'tab': 2}), ), ), const SizedBox(height: 12), // Tagihan Aktif Obx( () => _buildActivityCard( title: 'Tagihan Aktif', value: controller.tagihanAktifCount.value.toString(), icon: Icons.receipt_long_outlined, color: AppColors.warning, onTap: () => Get.toNamed(Routes.WARGA_SEWA, arguments: {'tab': 0}), ), ), const SizedBox(height: 12), // Denda Aktif Obx( () => _buildActivityCard( title: 'Denda Aktif', value: controller.dendaAktifCount.value.toString(), icon: Icons.warning_amber_outlined, color: AppColors.error, onTap: () => Get.toNamed(Routes.WARGA_SEWA, arguments: {'tab': 0}), ), ), ], ), ), ], ); } Widget _buildServiceCard({ required String title, required IconData icon, required Color color, required VoidCallback onTap, }) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(16), child: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [color.withOpacity(0.7), color], ), borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: color.withOpacity(0.3), blurRadius: 12, offset: const Offset(0, 6), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(16), child: Stack( children: [ // Background decoration Positioned( right: -15, bottom: -15, child: Container( width: 90, height: 90, decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), shape: BoxShape.circle, ), ), ), Positioned( left: -20, top: -20, child: Container( width: 60, height: 60, decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), shape: BoxShape.circle, ), ), ), // Icon and text Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Icon(icon, color: Colors.white, size: 24), ), Text( title, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16, ), ), ], ), ), ], ), ), ), ); } // Active rentals section with improved card design Widget _buildActiveRentalsSection(BuildContext context) { return Padding( padding: const EdgeInsets.fromLTRB(20, 8, 20, 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Sewa Aktif', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColors.textPrimary, ), ), TextButton.icon( onPressed: () => controller.onNavItemTapped(1), icon: const Icon(Icons.arrow_forward, size: 18), label: const Text('Lihat Semua'), style: TextButton.styleFrom(foregroundColor: AppColors.primary), ), ], ), const SizedBox(height: 12), Obx(() { if (controller.activeRentals.isEmpty) { return _buildEmptyState( message: 'Belum ada sewa aset yang aktif', icon: Icons.inventory_2_outlined, buttonText: 'Sewa Sekarang', onPressed: () => controller.navigateToRentals(), ); } return Column( children: controller.activeRentals .map((rental) => _buildModernRentalCard(rental)) .toList(), ); }), ], ), ); } // Empty state widget with consistent design Widget _buildEmptyState({ required String message, required IconData icon, required String buttonText, required VoidCallback onPressed, }) { return Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 32, horizontal: 24), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.03), blurRadius: 10, offset: const Offset(0, 4), ), ], border: Border.all(color: Colors.grey.shade100), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColors.primary.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon(icon, size: 40, color: AppColors.primary), ), const SizedBox(height: 20), Text( message, style: TextStyle( fontSize: 16, color: AppColors.textSecondary, fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), const SizedBox(height: 24), ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, foregroundColor: Colors.white, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), ), child: Text( buttonText, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600), ), ), ], ), ); } // Modern rental card with better layout Widget _buildModernRentalCard(Map rental) { return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), offset: const Offset(0, 4), blurRadius: 15, ), ], border: Border.all(color: Colors.grey.shade100, width: 1.0), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header with glass effect Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ AppColors.primary.withOpacity(0.04), AppColors.primary.withOpacity(0.08), ], ), borderRadius: const BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20), ), ), child: Row( children: [ // Asset icon/gambar Container( width: 48, height: 48, decoration: BoxDecoration( borderRadius: BorderRadius.circular(14), color: AppColors.primary.withOpacity(0.08), ), child: ClipRRect( borderRadius: BorderRadius.circular(14), child: rental['imageUrl'] != null && rental['imageUrl'].toString().isNotEmpty ? Image.network( rental['imageUrl'], fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) => Icon( Icons.local_shipping, color: AppColors.primary, size: 28, ), ) : Icon( Icons.local_shipping, color: AppColors.primary, size: 28, ), ), ), const SizedBox(width: 16), // Asset details Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( rental['name'] ?? '-', style: TextStyle( fontSize: 17, fontWeight: FontWeight.bold, color: AppColors.textPrimary, ), ), const SizedBox(height: 4), Text( rental['waktuSewa'] ?? '', style: TextStyle( fontSize: 13, color: AppColors.textSecondary, ), ), ], ), ), // Price tag Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: AppColors.primary.withOpacity(0.1), borderRadius: BorderRadius.circular(20), border: Border.all( color: AppColors.primary.withOpacity(0.3), width: 1.0, ), ), child: Text( rental['totalPrice'] ?? 'Rp 0', style: TextStyle( color: AppColors.primary, fontWeight: FontWeight.bold, fontSize: 14, ), ), ), ], ), ), // Details and actions Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), child: Column( children: [ // Details row Row( children: [ Expanded( child: _buildInfoItem( icon: Icons.timer_outlined, title: 'Durasi', value: rental['duration'] ?? '-', ), ), Expanded( child: _buildInfoItem( icon: Icons.calendar_today_outlined, title: 'Status', value: rental['status'] ?? '-', valueColor: AppColors.success, ), ), ], ), const SizedBox(height: 16), // Action buttons if ((rental['can_extend'] ?? false) == true) OutlinedButton.icon( onPressed: () => controller.extendRental(rental['id']), icon: const Icon(Icons.update, size: 18), label: const Text('Perpanjang'), style: OutlinedButton.styleFrom( foregroundColor: AppColors.primary, side: BorderSide(color: AppColors.primary), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), padding: const EdgeInsets.symmetric( vertical: 12, horizontal: 16, ), ), ), ], ), ), ], ), ); } // Info item for displaying details Widget _buildInfoItem({ required IconData icon, required String title, required String value, Color? valueColor, }) { return Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(10), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle(fontSize: 13, color: AppColors.textSecondary), ), const SizedBox(height: 4), Row( children: [ Icon(icon, size: 16, color: AppColors.primary), const SizedBox(width: 4), Text( value, style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, color: valueColor ?? AppColors.textPrimary, ), ), ], ), ], ), ); } // Build avatar fallback for when image is not available Widget _buildAvatarFallback() { return Center(child: Icon(Icons.person, color: Colors.white70, size: 30)); } // Get appropriate greeting based on time of day String _getGreeting() { final hour = DateTime.now().hour; if (hour < 12) { return 'Selamat Pagi'; } else if (hour < 17) { return 'Selamat Siang'; } else { return 'Selamat Malam'; } } // Build a summary card for activities Widget _buildActivityCard({ required String title, required String value, required IconData icon, required Color color, required VoidCallback onTap, }) { return Card( elevation: 1, shadowColor: Colors.black12, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: BorderSide(color: Colors.grey.shade200), ), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(12), child: Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: Icon(icon, color: color, size: 24), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 14, color: AppColors.textSecondary, ), ), const SizedBox(height: 4), Text( value, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColors.textPrimary, ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: AppColors.textSecondary.withOpacity(0.5), size: 16, ), ], ), ), ), ); } }