import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:penyaluran_app/app/modules/profile/controllers/profile_controller.dart'; import 'package:penyaluran_app/app/theme/app_theme.dart'; import 'dart:io'; class ProfileView extends GetView { const ProfileView({super.key}); // Helper untuk mengkonversi nilai role ke tampilan yang lebih baik String _formatRoleName(String? role) { if (role == null) return 'Pengguna'; switch (role.toLowerCase()) { case 'warga': return 'Warga'; case 'petugas_desa': return 'Petugas Desa'; case 'admin_desa': return 'Admin Desa'; case 'donatur': return 'Donatur'; case 'admin': return 'Administrator'; default: // Kapitalisasi setiap kata dan ganti underscore dengan spasi return role .split('_') .map((word) => word.isEmpty ? '' : '${word[0].toUpperCase()}${word.substring(1).toLowerCase()}') .join(' '); } } // Helper untuk mendapatkan warna berdasarkan role Color _getRoleColor(String? role) { if (role == null) return AppTheme.primaryColor; switch (role.toLowerCase()) { case 'warga': return AppTheme.infoColor; case 'petugas_desa': return AppTheme.primaryColor; case 'donatur': return AppTheme.successColor; default: return AppTheme.primaryColor; } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Profil'), actions: [ Obx(() { if (controller.isEditing.value) { return IconButton( icon: const Icon(Icons.save), onPressed: controller.updateProfile, ); } else { return IconButton( icon: const Icon(Icons.edit), onPressed: controller.toggleEditMode, ); } }), ], ), body: Obx(() { if (controller.isLoading.value) { return const Center(child: CircularProgressIndicator()); } return SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildProfileHeader(), const SizedBox(height: 24), _buildProfileForm(), const SizedBox(height: 24), _buildPasswordSection(context), ], ), ); }), ); } Widget _buildProfileHeader() { return Center( child: Column( children: [ Obx(() { // Jika user sedang dalam mode edit dan sudah memilih foto baru if (controller.isEditing.value && controller.fotoProfilPath.isNotEmpty) { return _buildProfileImage( isLocalFile: true, imagePath: controller.fotoProfilPath.value, ); } // Jika user sudah memiliki foto profil else if (controller.fotoProfil.isNotEmpty) { return _buildProfileImage( isLocalFile: false, imagePath: controller.fotoProfil.value, ); } // Default jika tidak ada foto else { return _buildDefaultProfileImage(); } }), // Tombol edit foto (hanya muncul dalam mode edit) Obx(() { if (controller.isEditing.value) { return Padding( padding: const EdgeInsets.only(top: 8.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // Tombol ambil dari kamera _buildPhotoActionButton( icon: Icons.camera_alt, label: 'Kamera', onPressed: () => controller.pickFotoProfilFromCamera(), ), const SizedBox(width: 8), // Tombol ambil dari galeri _buildPhotoActionButton( icon: Icons.photo_library, label: 'Galeri', onPressed: () => controller.pickFotoProfilFromGallery(), ), // Tombol hapus foto (hanya jika ada foto yang dipilih) if (controller.fotoProfilPath.isNotEmpty || controller.fotoProfil.isNotEmpty) Padding( padding: const EdgeInsets.only(left: 8.0), child: _buildPhotoActionButton( icon: Icons.delete, label: 'Hapus', onPressed: () => controller.clearFotoProfil(), color: Colors.red, ), ), ], ), ); } else { return const SizedBox.shrink(); } }), const SizedBox(height: 16), Obx(() => Text( controller.user.value?.name ?? 'Pengguna', style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, ), )), const SizedBox(height: 4), Obx(() { final role = controller.user.value?.role; final roleColor = _getRoleColor(role); return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), decoration: BoxDecoration( color: roleColor.withOpacity(0.1), borderRadius: BorderRadius.circular(16), border: Border.all(color: roleColor.withOpacity(0.3)), ), child: Text( _formatRoleName(role), style: TextStyle( fontSize: 14, color: roleColor, fontWeight: FontWeight.w500, ), ), ); }), ], ), ); } // Widget foto profil default Widget _buildDefaultProfileImage() { return CircleAvatar( radius: 60, backgroundColor: AppTheme.primaryColor.withOpacity(0.1), child: const Icon( Icons.person, size: 70, color: AppTheme.primaryColor, ), ); } // Widget foto profil dengan gambar Widget _buildProfileImage( {required bool isLocalFile, required String imagePath}) { return Stack( children: [ // Widget untuk menampilkan foto profil Container( width: 120, height: 120, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: AppTheme.primaryColor.withOpacity(0.5), width: 3, ), ), child: ClipRRect( borderRadius: BorderRadius.circular(60), child: isLocalFile ? Image.file( File(imagePath), fit: BoxFit.cover, width: 120, height: 120, errorBuilder: (context, error, stackTrace) => _buildDefaultProfileImage(), ) : Image.network( imagePath, fit: BoxFit.cover, width: 120, height: 120, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return Center( child: CircularProgressIndicator( value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null, ), ); }, errorBuilder: (context, error, stackTrace) => _buildDefaultProfileImage(), ), ), ), // Indikator loading saat mengupload if (controller.isUploadingFoto.value) Positioned.fill( child: Container( decoration: BoxDecoration( color: Colors.black38, shape: BoxShape.circle, ), child: Center( child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(Colors.white), ), ), ), ), ], ); } // Widget tombol aksi foto Widget _buildPhotoActionButton({ required IconData icon, required String label, required VoidCallback onPressed, Color? color, }) { final buttonColor = color ?? AppTheme.primaryColor; return InkWell( onTap: onPressed, borderRadius: BorderRadius.circular(8), child: Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: buttonColor.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all(color: buttonColor.withOpacity(0.3)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 16, color: buttonColor), const SizedBox(width: 4), Text( label, style: TextStyle( fontSize: 12, color: buttonColor, fontWeight: FontWeight.w500, ), ), ], ), ), ); } Widget _buildProfileForm() { return Obx(() { final isEditing = controller.isEditing.value; final user = controller.user.value; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Informasi Pribadi', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), // Nama TextField( controller: controller.nameController, decoration: InputDecoration( labelText: 'Nama Lengkap', border: OutlineInputBorder(), prefixIcon: Icon(Icons.person), enabled: isEditing, ), ), const SizedBox(height: 16), // Email TextField( controller: controller.emailController, decoration: InputDecoration( labelText: 'Email', border: OutlineInputBorder(), prefixIcon: Icon(Icons.email), enabled: false, // Email tidak bisa diubah ), keyboardType: TextInputType.emailAddress, ), const SizedBox(height: 16), // Nomor Telepon TextField( controller: controller.phoneController, decoration: InputDecoration( labelText: 'Nomor Telepon', border: OutlineInputBorder(), prefixIcon: Icon(Icons.phone), enabled: isEditing, ), keyboardType: TextInputType.phone, ), const SizedBox(height: 16), // Informasi tambahan sesuai role if (user != null) ...[ if (user.role?.toLowerCase() == 'warga') ...[ const SizedBox(height: 24), const Text( 'Informasi Warga', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), Obx(() { final roleData = controller.roleData.value; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildInfoRow( Icons.perm_identity, 'NIK', roleData?['nik'] ?? '-'), const SizedBox(height: 8), _buildInfoRow(Icons.wc, 'Jenis Kelamin', roleData?['jenis_kelamin'] ?? '-'), const SizedBox(height: 8), _buildInfoRow( Icons.home, 'Alamat', roleData?['alamat'] ?? '-'), if (user.desa != null) ...[ const SizedBox(height: 8), _buildInfoRow( Icons.location_city, 'Desa', user.desa!.nama), const SizedBox(height: 8), _buildInfoRow(Icons.location_on, 'Kecamatan', user.desa!.kecamatan ?? ''), const SizedBox(height: 8), _buildInfoRow(Icons.location_on, 'Kabupaten', user.desa!.kabupaten ?? ''), const SizedBox(height: 8), _buildInfoRow(Icons.location_on, 'Provinsi', user.desa!.provinsi ?? ''), ], ], ); }), ], if (user.role?.toLowerCase() == 'donatur') ...[ const SizedBox(height: 24), const Text( 'Informasi Donatur', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), Obx(() { final roleData = controller.roleData.value; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildInfoRow(Icons.business, 'Instansi', roleData?['instansi'] ?? '-'), const SizedBox(height: 8), _buildInfoRow( Icons.work, 'Jabatan', roleData?['jabatan'] ?? '-'), ], ); }), ], if (user.role?.toLowerCase() == 'petugas_desa') ...[ const SizedBox(height: 24), const Text( 'Informasi Petugas Desa', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), Obx(() { final roleData = controller.roleData.value; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildInfoRow(Icons.badge, 'NIP', roleData?['nip'] ?? '-'), if (user.desa != null) ...[ const SizedBox(height: 8), _buildInfoRow( Icons.location_city, 'Desa', user.desa!.nama), const SizedBox(height: 8), _buildInfoRow(Icons.location_on, 'Kecamatan', user.desa!.kecamatan ?? ''), const SizedBox(height: 8), _buildInfoRow(Icons.location_on, 'Kabupaten', user.desa!.kabupaten ?? ''), const SizedBox(height: 8), _buildInfoRow(Icons.location_on, 'Provinsi', user.desa!.provinsi ?? ''), ], ], ); }), ], ], ], ); }); } Widget _buildPasswordSection(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Keamanan', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), ElevatedButton.icon( onPressed: () => _showChangePasswordDialog(context), icon: const Icon(Icons.lock), label: const Text('Ubah Password'), style: ElevatedButton.styleFrom( backgroundColor: AppTheme.primaryColor, foregroundColor: Colors.white, minimumSize: const Size(double.infinity, 50), ), ), ], ); } void _showChangePasswordDialog(BuildContext context) { final currentPasswordController = TextEditingController(); final newPasswordController = TextEditingController(); final confirmPasswordController = TextEditingController(); Get.dialog( AlertDialog( title: const Text('Ubah Password'), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: currentPasswordController, decoration: const InputDecoration( labelText: 'Password Saat Ini', border: OutlineInputBorder(), ), obscureText: true, ), const SizedBox(height: 16), TextField( controller: newPasswordController, decoration: const InputDecoration( labelText: 'Password Baru', border: OutlineInputBorder(), ), obscureText: true, ), const SizedBox(height: 16), TextField( controller: confirmPasswordController, decoration: const InputDecoration( labelText: 'Konfirmasi Password Baru', border: OutlineInputBorder(), ), obscureText: true, ), ], ), ), actions: [ TextButton( onPressed: () => Get.back(), child: const Text('Batal'), ), ElevatedButton( onPressed: () { controller.changePassword( currentPasswordController.text, newPasswordController.text, confirmPasswordController.text, ); }, style: ElevatedButton.styleFrom( backgroundColor: AppTheme.primaryColor, ), child: const Text('Simpan'), ), ], ), ); } Widget _buildInfoRow(IconData icon, String label, String value) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(icon, size: 18, color: Colors.grey[700]), const SizedBox(width: 8), Expanded( child: Text( '$label: $value', style: TextStyle( fontSize: 14, color: Colors.grey[700], ), ), ), ], ); } }