import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:penyaluran_app/app/data/models/donatur_model.dart'; import 'package:penyaluran_app/app/data/models/penitipan_bantuan_model.dart'; import 'package:penyaluran_app/app/data/models/skema_bantuan_model.dart'; import 'package:penyaluran_app/app/data/models/penyaluran_bantuan_model.dart'; import 'package:penyaluran_app/app/data/models/laporan_penyaluran_model.dart'; import 'package:penyaluran_app/app/data/models/user_model.dart'; import 'package:penyaluran_app/app/data/models/stok_bantuan_model.dart'; import 'package:penyaluran_app/app/modules/auth/controllers/auth_controller.dart'; import 'package:penyaluran_app/app/services/supabase_service.dart'; import 'package:penyaluran_app/app/routes/app_pages.dart'; import 'package:image_picker/image_picker.dart'; class DonaturDashboardController extends GetxController { final AuthController _authController = Get.find(); final SupabaseService _supabaseService = SupabaseService.to; final Rx currentUser = Rx(null); // Variabel untuk foto profil final RxString fotoProfil = ''.obs; // Indeks tab yang aktif di bottom navigation bar final RxInt activeTabIndex = 0.obs; // Menyimpan ID skema bantuan yang dipilih final RxString selectedSkemaBantuanId = ''.obs; // Data untuk skema bantuan tersedia final RxList skemaBantuan = [].obs; // Data untuk jadwal penyaluran final RxList jadwalPenyaluran = [].obs; // Data untuk riwayat penitipan bantuan final RxList penitipanBantuan = [].obs; // Data untuk laporan penyaluran final RxList laporanPenyaluran = [].obs; // Data untuk stok bantuan yang tersedia final RxList stokBantuan = [].obs; // Indikator loading final RxBool isLoading = false.obs; // Jumlah notifikasi belum dibaca final RxInt jumlahNotifikasiBelumDibaca = 0.obs; // Data untuk foto bantuan pada form penitipan final RxList fotoBantuanPaths = [].obs; final ImagePicker _imagePicker = ImagePicker(); // Getter untuk data user BaseUserModel? get user => _authController.baseUser; String get role => user?.role ?? 'DONATUR'; String get nama { // Gunakan namaLengkap dari roleData jika tersedia if (_authController.isDonatur && _authController.roleData != null) { return _authController.roleData.namaLengkap ?? _authController.displayName; } // Gunakan displayName dari AuthController return _authController.displayName; } String? get desa => user?.desa?.nama; // Getter untuk alamat dan noHp String? get alamat { if (_authController.isDonatur && _authController.roleData != null) { return (_authController.roleData as DonaturModel).alamat; } return null; } String? get noHp { if (_authController.isDonatur && _authController.roleData != null) { return (_authController.roleData as DonaturModel).noHp; } return null; } // Getter untuk jenis donatur String? get jenis { if (_authController.isDonatur && _authController.roleData != null) { return (_authController.roleData as DonaturModel).jenis; } return null; } // Getter untuk foto profil String? get profilePhotoUrl { // 1. Coba ambil dari fotoProfil yang sudah disimpan if (fotoProfil.isNotEmpty) { return fotoProfil.value; } // 2. Coba ambil dari roleData jika merupakan DonaturModel if (_authController.isDonatur && _authController.roleData != null) { final donaturData = _authController.roleData as DonaturModel; if (donaturData.fotoProfil != null && donaturData.fotoProfil!.isNotEmpty) { return donaturData.fotoProfil; } } // 3. Coba ambil dari userData.roleData.fotoProfil final userData = _authController.userData; if (userData != null && userData.roleData is DonaturModel) { final donaturData = userData.roleData as DonaturModel; if (donaturData.fotoProfil != null && donaturData.fotoProfil!.isNotEmpty) { return donaturData.fotoProfil; } } return null; } @override void onInit() { super.onInit(); fetchData(); loadUserData(); } @override void onReady() { super.onReady(); // Perbarui data user dan foto profil saat halaman siap loadUserData(); } void loadUserData() { currentUser.value = _authController.baseUser; if (_authController.userData != null) { if (_authController.isDonatur) { var donaturData = _authController.roleData; // Ambil foto profil dari donaturData jika ada if (donaturData != null && donaturData.fotoProfil != null && donaturData.fotoProfil!.isNotEmpty) { fotoProfil.value = donaturData.fotoProfil!; } } } // Ambil foto profil dari database _fetchProfilePhoto(); } // Metode untuk mengambil foto profil Future _fetchProfilePhoto() async { try { if (user?.id == null) return; final donaturData = await _supabaseService.client .from('donatur') .select('foto_profil') .eq('id', user!.id) .maybeSingle(); if (donaturData != null && donaturData['foto_profil'] != null) { fotoProfil.value = donaturData['foto_profil']; } } catch (e) { print('Error fetching profile photo: $e'); } } void fetchData() async { isLoading.value = true; try { // Pastikan user sudah login dan memiliki ID if (user?.id == null) { throw Exception('User tidak terautentikasi'); } // Ambil data skema bantuan await fetchSkemaBantuan(); // Ambil data jadwal penyaluran await fetchJadwalPenyaluran(); // Ambil data penitipan bantuan await fetchPenitipanBantuan(); // Ambil data laporan penyaluran await fetchLaporanPenyaluran(); // Ambil data stok bantuan await fetchStokBantuan(); // Ambil data notifikasi await fetchNotifikasi(); } catch (e) { print('Error fetching data: $e'); } finally { isLoading.value = false; } } // Ambil data skema bantuan Future fetchSkemaBantuan() async { try { final response = await _supabaseService.client .from('xx02_skema_bantuan') .select() .order('created_at', ascending: false); skemaBantuan.value = response .map((data) => SkemaBantuanModel.fromJson(data)) .toList() .cast(); } catch (e) { print('Error fetching skema bantuan: $e'); } } // Ambil data jadwal penyaluran Future fetchJadwalPenyaluran() async { try { final now = DateTime.now(); final response = await _supabaseService.client .from('penyaluran_bantuan') .select( '*, lokasi_penyaluran:lokasi_penyaluran_id(*), kategori:kategori_bantuan_id(*), petugas:petugas_id(*)') .order('tanggal_penyaluran', ascending: true); // Konversi ke model lalu filter di sisi client final allJadwal = response .map((data) => PenyaluranBantuanModel.fromJson(data)) .toList() .cast(); // Filter jadwal yang tanggalnya lebih besar dari hari ini jadwalPenyaluran.value = allJadwal .where((jadwal) => jadwal.tanggalPenyaluran != null && jadwal.tanggalPenyaluran!.isAfter(now)) .toList(); } catch (e) { print('Error fetching jadwal penyaluran: $e'); } } // Ambil data penitipan bantuan Future fetchPenitipanBantuan() async { try { if (user?.id == null) return; final response = await _supabaseService.client .from('penitipan_bantuan') .select('*, donatur(*), stok_bantuan:stok_bantuan_id(*)') .eq('donatur_id', user!.id) .order('created_at', ascending: false); penitipanBantuan.value = response .map((data) => PenitipanBantuanModel.fromJson(data)) .toList() .cast(); } catch (e) { print('Error fetching penitipan bantuan: $e'); } } // Ambil data laporan penyaluran Future fetchLaporanPenyaluran() async { try { final response = await _supabaseService.client .from('laporan_penyaluran') .select() .order('created_at', ascending: false); laporanPenyaluran.value = response .map((data) => LaporanPenyaluranModel.fromJson(data)) .toList() .cast(); } catch (e) { print('Error fetching laporan penyaluran: $e'); } } // Ambil data stok bantuan Future fetchStokBantuan() async { try { final response = await _supabaseService.client .from('stok_bantuan') .select('*, kategori_bantuan:kategori_bantuan_id(*)') .order('nama', ascending: true); stokBantuan.value = response .map((data) => StokBantuanModel.fromJson(data)) .toList() .cast(); } catch (e) { print('Error fetching stok bantuan: $e'); } } // Ambil data notifikasi Future fetchNotifikasi() async { try { if (user?.id == null) return; final response = await _supabaseService.client .from('notifikasi') .select('*') .eq('user_id', user!.id) .eq('is_read', false) .count(); jumlahNotifikasiBelumDibaca.value = response.count ?? 0; } catch (e) { print('Error fetching notifikasi: $e'); } } // Fungsi untuk logout void logout() async { try { await _authController.logout(); Get.offAllNamed(Routes.login); } catch (e) { print('Error during logout: $e'); Get.snackbar( 'Error', 'Terjadi kesalahan saat logout: $e', snackPosition: SnackPosition.BOTTOM, ); } } // Mendapatkan daftar stok bantuan yang tersedia List getAvailableStokBantuan() { // Filter stok bantuan yang jumlahnya lebih dari 0 return stokBantuan.where((stok) => (stok.totalStok ?? 0) > 0).toList(); } // Ambil gambar dari kamera atau galeri Future pickImage({required bool isCamera}) async { try { final source = isCamera ? ImageSource.camera : ImageSource.gallery; final pickedFile = await _imagePicker.pickImage( source: source, imageQuality: 70, // Kurangi kualitas untuk menghemat ukuran ); if (pickedFile != null) { fotoBantuanPaths.add(pickedFile.path); } } catch (e) { print('Error picking image: $e'); Get.snackbar( 'Gagal', 'Terjadi kesalahan saat mengambil gambar', backgroundColor: Colors.red, colorText: Colors.white, ); } } // Hapus foto bantuan dari daftar void removeFotoBantuan(int index) { if (index >= 0 && index < fotoBantuanPaths.length) { fotoBantuanPaths.removeAt(index); } } // Reset foto bantuan paths void resetFotoBantuan() { fotoBantuanPaths.clear(); } // Membuat penitipan bantuan baru Future createPenitipanBantuan( String? stokBantuanId, double jumlah, String deskripsi, String? skemaBantuanId, ) async { try { isLoading.value = true; if (user?.id == null) { throw Exception('User tidak terautentikasi'); } if (stokBantuanId == null) { throw Exception('Stok bantuan harus dipilih'); } if (fotoBantuanPaths.isEmpty) { throw Exception('Foto bantuan harus diunggah'); } // Dapatkan informasi stok bantuan untuk mendapatkan nilai is_uang final selectedStokBantuan = stokBantuan.firstWhere( (stok) => stok.id == stokBantuanId, orElse: () => StokBantuanModel(), ); // Unggah foto bantuan ke storage menggunakan metode dari SupabaseService final fotoBantuanUrls = await _supabaseService.uploadMultipleFiles( fotoBantuanPaths, 'bantuan', 'foto_bantuan'); if (fotoBantuanUrls == null || fotoBantuanUrls.isEmpty) { throw 'Gagal mengupload foto bantuan'; } // Data yang akan disimpan final Map data = { 'donatur_id': user!.id, 'stok_bantuan_id': stokBantuanId, 'jumlah': jumlah, 'deskripsi': deskripsi, 'status': 'MENUNGGU', 'tanggal_penitipan': DateTime.now().toIso8601String(), 'foto_bantuan': fotoBantuanUrls, 'is_uang': selectedStokBantuan.isUang ?? false, }; // Tambahkan skema bantuan jika ada if (skemaBantuanId != null && skemaBantuanId.isNotEmpty) { data['skema_bantuan_id'] = skemaBantuanId; } // Simpan ke database await _supabaseService.client.from('penitipan_bantuan').insert(data); // Reset foto bantuan setelah berhasil disimpan resetFotoBantuan(); // Ambil data penitipan bantuan yang baru await fetchPenitipanBantuan(); // Tampilkan pesan sukses Get.snackbar( 'Berhasil', 'Penitipan bantuan berhasil dikirim dan akan diproses oleh petugas desa', backgroundColor: Colors.green, colorText: Colors.white, duration: const Duration(seconds: 3), ); } catch (e) { print('Error creating penitipan bantuan: $e'); Get.snackbar( 'Gagal', 'Terjadi kesalahan saat mengirim penitipan bantuan: $e', backgroundColor: Colors.red, colorText: Colors.white, duration: const Duration(seconds: 3), ); } finally { isLoading.value = false; } } // Mendapatkan nama lokasi penyaluran berdasarkan ID Future getLokasiPenyaluran(String? lokasiId) async { if (lokasiId == null) return null; try { final response = await _supabaseService.client .from('lokasi_penyaluran') .select('nama') .eq('id', lokasiId) .single(); if (response != null && response['nama'] != null) { return response['nama'] as String; } return null; } catch (e) { print('Error fetching lokasi penyaluran: $e'); return null; } } }