Perbarui model dan tampilan untuk menambahkan properti fotoProfil di DonaturModel, PetugasDesaModel, dan WargaModel. Modifikasi controller dan tampilan untuk mendukung pengambilan dan penampilan foto profil pengguna. Tambahkan fungsionalitas baru untuk menampilkan foto profil di berbagai tampilan, termasuk detail penerima dan dashboard warga. Perbarui rute aplikasi untuk mencakup halaman profil pengguna.

This commit is contained in:
Khafidh Fuadi
2025-03-25 12:21:37 +07:00
parent 8e9553d1fc
commit 32736be867
19 changed files with 2138 additions and 752 deletions

View File

@ -1,5 +1,6 @@
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:penyaluran_app/app/services/supabase_service.dart';
import 'package:penyaluran_app/app/utils/date_time_helper.dart';
class PenerimaController extends GetxController {
@ -7,6 +8,11 @@ class PenerimaController extends GetxController {
<Map<String, dynamic>>[].obs;
final RxBool isLoading = false.obs;
// Variabel untuk menyimpan daftar penyaluran bantuan untuk penerima tertentu
final RxList<Map<String, dynamic>> daftarPenyaluran =
<Map<String, dynamic>>[].obs;
final RxBool isLoadingPenyaluran = false.obs;
// Variabel untuk halaman konfirmasi penerima
final RxBool isKonfirmasiChecked = false.obs;
final RxBool isIdentitasChecked = false.obs;
@ -37,9 +43,30 @@ class PenerimaController extends GetxController {
super.onClose();
}
void fetchDaftarPenerima() {
void fetchDaftarPenerima() async {
isLoading.value = true;
try {
// Get data penerima dari database
final penerimaBantuan = await SupabaseService.to.getPenerimaBantuan();
if (penerimaBantuan != null) {
daftarPenerima.value = penerimaBantuan;
} else {
// Gunakan data dummy jika gagal mendapatkan data dari database
_loadDummyData();
}
} catch (e) {
print('Error fetching penerima: $e');
// Gunakan data dummy sebagai fallback
_loadDummyData();
} finally {
isLoading.value = false;
}
}
// Metode untuk memuat data dummy
void _loadDummyData() {
// Simulasi data penerima
Future.delayed(const Duration(milliseconds: 500), () {
daftarPenerima.value = [
@ -134,7 +161,6 @@ class PenerimaController extends GetxController {
'terverifikasi': true,
},
];
isLoading.value = false;
});
}
@ -167,6 +193,79 @@ class PenerimaController extends GetxController {
}
}
// Metode untuk mengambil daftar penyaluran bantuan berdasarkan ID warga
Future<void> fetchPenyaluranByWargaId(String wargaId) async {
isLoadingPenyaluran.value = true;
daftarPenyaluran.clear();
try {
final penyaluranBantuan =
await SupabaseService.to.getPenyaluranBantuanByWargaId(wargaId);
if (penyaluranBantuan != null && penyaluranBantuan.isNotEmpty) {
daftarPenyaluran.value = penyaluranBantuan;
} else {
// Gunakan data dummy jika tidak ada data dari database
_loadDummyPenyaluran(wargaId);
}
} catch (e) {
print('Error fetching penyaluran bantuan: $e');
// Gunakan data dummy sebagai fallback
_loadDummyPenyaluran(wargaId);
} finally {
isLoadingPenyaluran.value = false;
}
}
// Metode untuk memuat data dummy penyaluran
void _loadDummyPenyaluran(String wargaId) {
// Data dummy penyaluran bantuan (hanya untuk demo)
daftarPenyaluran.value = [
{
'id': '1',
'penerima_id': wargaId,
'tanggal_penyaluran':
DateTime.now().subtract(const Duration(days: 5)).toIso8601String(),
'status': 'TERLAKSANA',
'stok_bantuan': {
'nama': 'Paket Sembako',
'jenis': 'Bahan Pokok',
'kuantitas': '1 Paket',
},
'keterangan': 'Bantuan pangan rutin bulanan',
'bukti_penyaluran': 'assets/images/bukti_penyaluran.jpg',
},
{
'id': '2',
'penerima_id': wargaId,
'tanggal_penyaluran':
DateTime.now().subtract(const Duration(days: 35)).toIso8601String(),
'status': 'TERLAKSANA',
'stok_bantuan': {
'nama': 'Bantuan Pendidikan',
'jenis': 'Alat Tulis',
'kuantitas': '1 Paket',
},
'keterangan': 'Bantuan sekolah semester baru',
'bukti_penyaluran': 'assets/images/bukti_penyaluran.jpg',
},
{
'id': '3',
'penerima_id': wargaId,
'tanggal_penyaluran':
DateTime.now().add(const Duration(days: 2)).toIso8601String(),
'status': 'DIJADWALKAN',
'stok_bantuan': {
'nama': 'Paket Sembako',
'jenis': 'Bahan Pokok',
'kuantitas': '1 Paket',
},
'keterangan': 'Bantuan pangan rutin bulanan',
'bukti_penyaluran': null,
},
];
}
// Fungsi untuk memilih tanggal penyaluran
Future<void> pilihTanggalPenyaluran(BuildContext context) async {
final DateTime? picked = await showDatePicker(

View File

@ -27,6 +27,9 @@ class PetugasDesaController extends GetxController {
// Data profil pengguna dari cache
final RxMap<String, dynamic> userProfile = RxMap<String, dynamic>({});
// Variabel untuk foto profil
final RxString fotoProfil = ''.obs;
// Model desa dari cache
final Rx<DesaModel?> desaModel = Rx<DesaModel?>(null);
@ -102,6 +105,33 @@ class PetugasDesaController extends GetxController {
return 'Petugas Desa';
}
// 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 PetugasDesaModel
final userData = _authController.userData;
if (userData != null && userData.roleData is PetugasDesaModel) {
final petugasData = userData.roleData as PetugasDesaModel;
if (petugasData.fotoProfil != null &&
petugasData.fotoProfil!.isNotEmpty) {
return petugasData.fotoProfil;
}
}
// 3. Coba ambil dari role_data di userProfile
if (userProfile['role_data'] != null &&
userProfile['role_data'] is Map<String, dynamic> &&
userProfile['role_data']['foto_profil'] != null) {
return userProfile['role_data']['foto_profil'];
}
return null;
}
// Getter untuk counter dari CounterService
RxInt get jumlahNotifikasiBelumDibaca =>
_counterService.jumlahNotifikasiBelumDibaca;
@ -212,6 +242,14 @@ class PetugasDesaController extends GetxController {
'desa': petugasData.desa?.toJson(),
};
// Ambil foto profil jika ada
if (petugasData.fotoProfil != null &&
petugasData.fotoProfil!.isNotEmpty) {
fotoProfil.value = petugasData.fotoProfil!;
print(
'DEBUG: Foto profil dari petugasData: ${fotoProfil.value}');
}
return; // Data sudah lengkap, tidak perlu fetch lagi
}
}
@ -223,6 +261,14 @@ class PetugasDesaController extends GetxController {
if (baseProfile != null) {
userProfile.value = baseProfile;
// Cek dan ambil foto profil
if (baseProfile['role_data'] != null &&
baseProfile['role_data'] is Map<String, dynamic> &&
baseProfile['role_data']['foto_profil'] != null) {
fotoProfil.value = baseProfile['role_data']['foto_profil'];
print('DEBUG: Foto profil dari API: ${fotoProfil.value}');
}
if (baseProfile['desa'] != null &&
baseProfile['desa'] is Map<String, dynamic>) {
try {
@ -594,7 +640,9 @@ class PetugasDesaController extends GetxController {
// Metode untuk mengubah tab aktif
void changeTab(int index) {
print('Mengubah tab ke index: $index (dari: ${activeTabIndex.value})');
activeTabIndex.value = index;
print('activeTabIndex sekarang: ${activeTabIndex.value}');
// Jika tab penitipan dipilih, muat ulang data penitipan
if (index == 2) {
@ -621,6 +669,8 @@ class PetugasDesaController extends GetxController {
print('Error saat memanggil onTabReactivated: $e');
}
}
// Paksa update UI
activeTabIndex.refresh();
}
// Metode untuk logout