import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:penyaluran_app/app/modules/donatur/controllers/donatur_dashboard_controller.dart'; import 'package:penyaluran_app/app/routes/app_pages.dart'; import 'package:penyaluran_app/app/utils/format_helper.dart'; import 'package:penyaluran_app/app/widgets/section_header.dart'; class DonaturDashboardView extends GetView { const DonaturDashboardView({super.key}); @override DonaturDashboardController get controller { if (!Get.isRegistered( tag: 'donatur_dashboard')) { return Get.put(DonaturDashboardController(), tag: 'donatur_dashboard', permanent: true); } return Get.find(tag: 'donatur_dashboard'); } @override Widget build(BuildContext context) { return Scaffold( body: Obx(() { if (controller.isLoading.value) { return const Center(child: CircularProgressIndicator()); } return RefreshIndicator( onRefresh: () async { controller.fetchData(); }, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildWelcomeSection(), const SizedBox(height: 24), _buildStatisticSection(), ], ), ), ); }), ); } Widget _buildWelcomeSection() { return Container( margin: const EdgeInsets.only(bottom: 8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.blue.withOpacity(0.1), blurRadius: 15, offset: const Offset(0, 5), ), ], ), child: Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), child: Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), gradient: LinearGradient( colors: [Colors.white, Colors.blue.shade50], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: Colors.blue.shade200, width: 2), boxShadow: [ BoxShadow( color: Colors.blue.withOpacity(0.2), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Hero( tag: 'donatur-profile', child: CircleAvatar( radius: 30, backgroundColor: Colors.blue.shade100, backgroundImage: controller.profilePhotoUrl != null && controller.profilePhotoUrl!.isNotEmpty ? NetworkImage(controller.profilePhotoUrl!) : null, child: (controller.profilePhotoUrl == null || controller.profilePhotoUrl!.isEmpty) ? Text( controller.nama.isNotEmpty ? controller.nama .toString() .substring(0, 1) .toUpperCase() : '?', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.blue.shade700, fontSize: 24, ), ) : null, ), ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Selamat Datang,', style: TextStyle( fontSize: 14, color: Colors.blue.shade700, fontWeight: FontWeight.w500, ), ), Text( controller.nama, style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.blue.shade900, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), ], ), const SizedBox(height: 20), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(15), boxShadow: [ BoxShadow( color: Colors.blue.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: Column( children: [ _buildInfoRow( icon: Icons.home_rounded, iconColor: Colors.blue.shade300, label: 'Alamat', value: controller.alamat ?? 'Alamat tidak tersedia', ), const Padding( padding: EdgeInsets.symmetric(vertical: 8), child: Divider(height: 1), ), _buildInfoRow( icon: Icons.phone_rounded, iconColor: Colors.green.shade300, label: 'No. HP', value: controller.noHp ?? 'No. HP tidak tersedia', ), const Padding( padding: EdgeInsets.symmetric(vertical: 8), child: Divider(height: 1), ), _buildInfoRow( icon: Icons.category_rounded, iconColor: Colors.amber.shade300, label: 'Jenis Donatur', value: controller.jenis ?? 'Jenis tidak tersedia', ), ], ), ), const SizedBox(height: 16), _buildActionButton( icon: Icons.add_box_rounded, label: 'Titip Bantuan', color: Colors.green.shade700, onTap: () { // Navigasi ke form penitipan bantuan controller.activeTabIndex.value = 3; }, ), ], ), ), ), ); } Widget _buildStatisticSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SectionHeader( title: 'Statistik Kontribusi', ), Text( 'Ringkasan aktivitas anda sebagai donatur', style: TextStyle( fontSize: 14, color: Colors.grey.shade600, ), ), const SizedBox(height: 16), Row( children: [ Expanded( child: _buildStatCard( title: 'Total Bantuan', value: '${controller.penitipanBantuan.length}', icon: Icons.card_giftcard, color: Colors.blue, ), ), const SizedBox(width: 12), Expanded( child: _buildStatCard( title: 'Menunggu Verifikasi', value: '${controller.penitipanBantuan.where((p) => p.status == 'MENUNGGU').length}', icon: Icons.hourglass_empty, color: Colors.orange, ), ), ], ), const SizedBox(height: 12), Row( children: [ Expanded( child: _buildStatCard( title: 'Diterima', value: '${controller.penitipanBantuan.where((p) => p.status == 'TERVERIFIKASI').length}', icon: Icons.check_circle_outline, color: Colors.green, ), ), const SizedBox(width: 12), Expanded( child: _buildStatCard( title: 'Ditolak', value: '${controller.penitipanBantuan.where((p) => p.status == 'DITOLAK').length}', icon: Icons.cancel_outlined, color: Colors.red, ), ), ], ), ], ); } Widget _buildInfoRow({ required IconData icon, required Color iconColor, required String label, required String value, }) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: iconColor.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: Icon( icon, size: 16, color: iconColor, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: TextStyle( fontSize: 12, color: Colors.grey.shade600, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 2), Text( value, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, ), ), ], ), ), ], ); } Widget _buildActionButton({ required IconData icon, required String label, required Color color, required VoidCallback onTap, }) { return ElevatedButton( onPressed: onTap, style: ElevatedButton.styleFrom( foregroundColor: Colors.white, backgroundColor: color, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), elevation: 0, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, size: 16), const SizedBox(width: 8), Text(label), ], ), ); } Widget _buildStatCard({ required String title, required String value, required IconData icon, required Color color, }) { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: color.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Icon( icon, color: color, size: 24, ), ), const SizedBox(height: 12), Text( title, style: TextStyle( fontSize: 12, color: Colors.grey.shade600, ), ), const SizedBox(height: 4), Text( value, style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: color, ), ), ], ), ), ), ); } Widget _buildEventCard(dynamic event) { final formattedDate = event.tanggalPenyaluran != null ? FormatHelper.formatDateTime(event.tanggalPenyaluran!) : 'Tanggal tidak tersedia'; return Container( margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(12), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 50, height: 50, alignment: Alignment.center, decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(10), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.event, color: Colors.blue.shade700, size: 24, ), Text( event.tanggalPenyaluran != null ? FormatHelper.formatDateTime( event.tanggalPenyaluran!) : '--', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.blue.shade700, ), ), ], ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( event.nama ?? 'Penyaluran Bantuan', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), Text( formattedDate, style: TextStyle( fontSize: 14, color: Colors.grey.shade600, ), ), const SizedBox(height: 4), Text( event.deskripsi ?? 'Tidak ada deskripsi', style: const TextStyle(fontSize: 14), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), ], ), ), ), ); } Widget _buildPenitipanCard(dynamic penitipan) { final formattedDate = penitipan.tanggalPenitipan != null ? FormatHelper.formatDateTime(penitipan.tanggalPenitipan!) : 'Tanggal tidak tersedia'; Color statusColor; IconData statusIcon; switch (penitipan.status) { case 'DITERIMA': statusColor = Colors.green; statusIcon = Icons.check_circle; break; case 'DITOLAK': statusColor = Colors.red; statusIcon = Icons.cancel; break; case 'MENUNGGU': default: statusColor = Colors.orange; statusIcon = Icons.hourglass_empty; break; } return Container( margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(12), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 50, height: 50, alignment: Alignment.center, decoration: BoxDecoration( color: statusColor.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: Icon( statusIcon, color: statusColor, size: 24, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( penitipan.kategoriBantuan?.nama ?? 'Bantuan', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4), decoration: BoxDecoration( color: statusColor.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Text( penitipan.status ?? 'MENUNGGU', style: TextStyle( fontSize: 12, color: statusColor, fontWeight: FontWeight.bold, ), ), ), ], ), const SizedBox(height: 4), Text( formattedDate, style: TextStyle( fontSize: 14, color: Colors.grey.shade600, ), ), const SizedBox(height: 4), Row( children: [ Icon( Icons.inventory_2_outlined, size: 14, color: Colors.grey.shade600, ), const SizedBox(width: 4), Text( 'Jumlah: ${penitipan.jumlah ?? 0}', style: TextStyle( fontSize: 14, color: Colors.grey.shade800, ), ), ], ), ], ), ), ], ), ), ), ); } }