Perbarui dependensi dan konfigurasi lokal untuk mendukung fitur baru

- Tambahkan dependensi baru: syncfusion_flutter_calendar, syncfusion_localizations, dan flutter_localizations di pubspec.yaml
- Perbarui konfigurasi lokal di main.dart untuk mendukung bahasa Indonesia dan menambahkan delegasi lokal
- Modifikasi model PenyaluranBantuan untuk memastikan format tanggal menggunakan UTC
- Perbarui tampilan dan logika di beberapa widget untuk meningkatkan pengalaman pengguna dan konsistensi data
- Ganti posisi snack bar dari bawah ke atas untuk notifikasi yang lebih baik
This commit is contained in:
Khafidh Fuadi
2025-03-14 08:09:54 +07:00
parent b0310103fe
commit 7c94b85434
25 changed files with 2187 additions and 309 deletions

View File

@ -6,6 +6,8 @@ import 'package:penyaluran_app/app/data/models/kategori_bantuan_model.dart';
import 'package:penyaluran_app/app/data/models/user_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/utils/date_time_helper.dart';
import 'dart:async';
class JadwalPenyaluranController extends GetxController {
final AuthController _authController = Get.find<AuthController>();
@ -47,14 +49,99 @@ class JadwalPenyaluranController extends GetxController {
loadPermintaanPenjadwalanData();
loadLokasiPenyaluranData();
loadKategoriBantuanData();
// Jalankan timer untuk memeriksa jadwal secara berkala
_startJadwalCheckTimer();
}
@override
void onClose() {
searchController.dispose();
// Hentikan timer jika ada
_stopJadwalCheckTimer();
super.onClose();
}
// Timer untuk memeriksa jadwal secara berkala
Timer? _jadwalCheckTimer;
void _startJadwalCheckTimer() {
// Periksa jadwal setiap 1 menit
_jadwalCheckTimer = Timer.periodic(const Duration(minutes: 1), (_) {
checkAndUpdateJadwalStatus();
});
// Periksa jadwal segera saat aplikasi dimulai
checkAndUpdateJadwalStatus();
}
void _stopJadwalCheckTimer() {
_jadwalCheckTimer?.cancel();
_jadwalCheckTimer = null;
}
// Memeriksa dan memperbarui status jadwal
Future<void> checkAndUpdateJadwalStatus() async {
try {
// Dapatkan tanggal dan waktu saat ini dalam timezone lokal
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
// Periksa jadwal mendatang yang tanggalnya hari ini
List<PenyaluranBantuanModel> jadwalToUpdate = [];
for (var jadwal in jadwalMendatang) {
if (jadwal.tanggalPenyaluran != null) {
// Konversi tanggal jadwal ke timezone lokal
final jadwalDateTime =
DateTimeHelper.toLocalDateTime(jadwal.tanggalPenyaluran!);
final jadwalDate = DateTime(
jadwalDateTime.year,
jadwalDateTime.month,
jadwalDateTime.day,
);
// Jika tanggal jadwal adalah hari ini
if (isSameDay(jadwalDate, today)) {
jadwalToUpdate.add(jadwal);
// Jika waktu jadwal sudah tiba atau lewat
if (now.isAfter(jadwalDateTime) ||
now.isAtSameMomentAs(jadwalDateTime)) {
// Ubah status menjadi BERLANGSUNG (aktif)
await _supabaseService.updateJadwalStatus(
jadwal.id!, 'BERLANGSUNG');
}
}
}
}
// Refresh data setelah pembaruan
if (jadwalToUpdate.isNotEmpty) {
await loadJadwalData();
// Tampilkan notifikasi jika ada jadwal yang dipindahkan
Get.snackbar(
'Jadwal Diperbarui',
'${jadwalToUpdate.length} jadwal dipindahkan ke section Hari Ini',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
duration: const Duration(seconds: 3),
);
}
} catch (e) {
print('Error checking and updating jadwal status: $e');
}
}
// Helper method untuk memeriksa apakah dua tanggal adalah hari yang sama
bool isSameDay(DateTime date1, DateTime date2) {
return date1.year == date2.year &&
date1.month == date2.month &&
date1.day == date2.day;
}
Future<void> loadJadwalData() async {
isLoading.value = true;
try {
@ -155,7 +242,7 @@ class JadwalPenyaluranController extends GetxController {
Get.snackbar(
'Sukses',
'Jadwal berhasil disetujui',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -164,7 +251,7 @@ class JadwalPenyaluranController extends GetxController {
Get.snackbar(
'Error',
'Gagal menyetujui jadwal: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -181,7 +268,7 @@ class JadwalPenyaluranController extends GetxController {
Get.snackbar(
'Sukses',
'Jadwal berhasil ditolak',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -190,7 +277,7 @@ class JadwalPenyaluranController extends GetxController {
Get.snackbar(
'Error',
'Gagal menolak jadwal: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -207,7 +294,7 @@ class JadwalPenyaluranController extends GetxController {
Get.snackbar(
'Sukses',
'Jadwal berhasil diselesaikan',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -216,7 +303,7 @@ class JadwalPenyaluranController extends GetxController {
Get.snackbar(
'Error',
'Gagal menyelesaikan jadwal: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);

View File

@ -78,7 +78,7 @@ class LaporanController extends GetxController {
Get.snackbar(
'Sukses',
'Laporan berhasil dibuat',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -88,7 +88,7 @@ class LaporanController extends GetxController {
Get.snackbar(
'Error',
'Gagal membuat laporan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -106,7 +106,7 @@ class LaporanController extends GetxController {
Get.snackbar(
'Sukses',
'Laporan berhasil diunduh',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -116,7 +116,7 @@ class LaporanController extends GetxController {
Get.snackbar(
'Error',
'Gagal mengunduh laporan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -133,7 +133,7 @@ class LaporanController extends GetxController {
Get.snackbar(
'Sukses',
'Laporan berhasil dihapus',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -142,7 +142,7 @@ class LaporanController extends GetxController {
Get.snackbar(
'Error',
'Gagal menghapus laporan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);

View File

@ -102,7 +102,7 @@ class PenerimaBantuanController extends GetxController {
Get.snackbar(
'Sukses',
'Penerima bantuan berhasil ditambahkan',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -111,7 +111,7 @@ class PenerimaBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal menambahkan penerima bantuan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -147,7 +147,7 @@ class PenerimaBantuanController extends GetxController {
Get.snackbar(
'Sukses',
'Penerima bantuan berhasil diperbarui',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -156,7 +156,7 @@ class PenerimaBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal memperbarui penerima bantuan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -173,7 +173,7 @@ class PenerimaBantuanController extends GetxController {
Get.snackbar(
'Sukses',
'Penerima bantuan berhasil dinonaktifkan',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -182,7 +182,7 @@ class PenerimaBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal menonaktifkan penerima bantuan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -199,7 +199,7 @@ class PenerimaBantuanController extends GetxController {
Get.snackbar(
'Sukses',
'Penerima bantuan berhasil diaktifkan',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -208,7 +208,7 @@ class PenerimaBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal mengaktifkan penerima bantuan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);

View File

@ -76,7 +76,7 @@ class PengaduanController extends GetxController {
Get.snackbar(
'Sukses',
'Pengaduan berhasil diproses',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -85,7 +85,7 @@ class PengaduanController extends GetxController {
Get.snackbar(
'Error',
'Gagal memproses pengaduan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -120,7 +120,7 @@ class PengaduanController extends GetxController {
Get.snackbar(
'Sukses',
'Tindakan berhasil ditambahkan',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -129,7 +129,7 @@ class PengaduanController extends GetxController {
Get.snackbar(
'Error',
'Gagal menambahkan tindakan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -146,7 +146,7 @@ class PengaduanController extends GetxController {
Get.snackbar(
'Sukses',
'Pengaduan berhasil diselesaikan',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -155,7 +155,7 @@ class PengaduanController extends GetxController {
Get.snackbar(
'Error',
'Gagal menyelesaikan pengaduan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);

View File

@ -214,7 +214,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal mengambil gambar: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -237,7 +237,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal mengambil gambar: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -261,7 +261,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Error',
'Foto bantuan harus diupload',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -291,7 +291,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Sukses',
'Penitipan bantuan berhasil ditambahkan',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -300,7 +300,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal menambahkan penitipan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -315,7 +315,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Error',
'Bukti serah terima harus diupload',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -339,7 +339,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Sukses',
'Penitipan berhasil diverifikasi',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -348,7 +348,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal memverifikasi penitipan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -369,7 +369,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Sukses',
'Penitipan berhasil ditolak',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -378,7 +378,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal menolak penitipan: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -666,7 +666,7 @@ class PenitipanBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal menambahkan donatur: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);

View File

@ -19,6 +19,10 @@ class PetugasDesaController extends GetxController {
// Controller untuk pencarian
final TextEditingController searchController = TextEditingController();
// Controller untuk pencarian penerima
final TextEditingController searchPenerimaController =
TextEditingController();
// Data profil pengguna dari cache
final RxMap<String, dynamic> userProfile = RxMap<String, dynamic>({});
@ -28,6 +32,23 @@ class PetugasDesaController extends GetxController {
// Data jadwal hari ini
final RxList<dynamic> jadwalHariIni = <dynamic>[].obs;
// Data penerima penyaluran
final RxList<Map<String, dynamic>> penerimaPenyaluran =
<Map<String, dynamic>>[].obs;
final RxList<Map<String, dynamic>> filteredPenerima =
<Map<String, dynamic>>[].obs;
final RxInt jumlahPenerima = 0.obs;
final RxString filterStatus = 'SEMUA'.obs;
// Tambahkan variabel isLoading
final isLoading = false.obs;
// Tambahkan instance supabaseService yang sudah diinisialisasi
final supabaseService = SupabaseService.to;
// Variabel untuk pencarian dan filter
final searchQuery = ''.obs;
UserModel? get user => _authController.user;
String get role => user?.role ?? 'PETUGASDESA';
String get nama => user?.name ?? 'Petugas Desa';
@ -81,6 +102,7 @@ class PetugasDesaController extends GetxController {
@override
void onClose() {
searchController.dispose();
searchPenerimaController.dispose();
super.onClose();
}
@ -216,6 +238,258 @@ class PetugasDesaController extends GetxController {
}
}
// Metode untuk memastikan format UUID yang benar
String ensureValidUUID(String id) {
// Jika ID sudah dalam format UUID yang benar, kembalikan apa adanya
if (id.contains('-') && id.length == 36) {
return id;
}
// Jika ID adalah string UUID tanpa tanda hubung, tambahkan tanda hubung
if (id.length == 32) {
return '${id.substring(0, 8)}-${id.substring(8, 12)}-${id.substring(12, 16)}-${id.substring(16, 20)}-${id.substring(20)}';
}
// Jika format tidak dikenali, kembalikan apa adanya
return id;
}
// Metode untuk memuat ulang data penerima
Future<void> reloadPenerimaPenyaluran() async {
isLoading.value = true;
try {
// Gunakan data dummy sementara
final dummyData = _createDummyPenerimaPenyaluran();
penerimaPenyaluran.value = dummyData;
jumlahPenerima.value = dummyData.length;
print(
'Data dummy penerima berhasil dimuat: ${penerimaPenyaluran.length} data');
} catch (e) {
print('Error saat memuat data dummy penerima: $e');
} finally {
isLoading.value = false;
}
}
// Membuat data dummy penerima penyaluran
List<Map<String, dynamic>> _createDummyPenerimaPenyaluran() {
return [
{
'id': 1,
'penyaluran_bantuan_id': 'a2dabc5a-761f-4f11-9fbe-a376768880c3',
'warga_id': 'warga-001',
'status_penerimaan': 'SUDAHMENERIMA',
'jumlah_bantuan': 1,
'created_at': '2023-01-01',
'warga': {
'id': 'warga-001',
'nama_lengkap': 'Budi Santoso',
'nik': '3201234567890001',
'alamat': 'Jl. Merdeka No. 123, RT 01/RW 02',
'jenis_kelamin': 'L',
'tanggal_lahir': '1980-01-01',
}
},
{
'id': 2,
'penyaluran_bantuan_id': 'a2dabc5a-761f-4f11-9fbe-a376768880c3',
'warga_id': 'warga-002',
'status_penerimaan': 'BELUMMENERIMA',
'jumlah_bantuan': 1,
'created_at': '2023-01-01',
'warga': {
'id': 'warga-002',
'nama_lengkap': 'Siti Aminah',
'nik': '3201234567890002',
'alamat': 'Jl. Pahlawan No. 45, RT 03/RW 04',
'jenis_kelamin': 'P',
'tanggal_lahir': '1985-05-15',
}
},
{
'id': 3,
'penyaluran_bantuan_id': 'a2dabc5a-761f-4f11-9fbe-a376768880c3',
'warga_id': 'warga-003',
'status_penerimaan': 'SUDAHMENERIMA',
'jumlah_bantuan': 1,
'created_at': '2023-01-01',
'warga': {
'id': 'warga-003',
'nama_lengkap': 'Ahmad Hidayat',
'nik': '3201234567890003',
'alamat': 'Jl. Cendrawasih No. 78, RT 05/RW 06',
'jenis_kelamin': 'L',
'tanggal_lahir': '1975-12-10',
}
},
{
'id': 4,
'penyaluran_bantuan_id': 'a2dabc5a-761f-4f11-9fbe-a376768880c3',
'warga_id': 'warga-004',
'status_penerimaan': 'BELUMMENERIMA',
'jumlah_bantuan': 1,
'created_at': '2023-01-01',
'warga': {
'id': 'warga-004',
'nama_lengkap': 'Dewi Lestari',
'nik': '3201234567890004',
'alamat': 'Jl. Mawar No. 12, RT 07/RW 08',
'jenis_kelamin': 'P',
'tanggal_lahir': '1990-08-22',
}
},
{
'id': 5,
'penyaluran_bantuan_id': 'a2dabc5a-761f-4f11-9fbe-a376768880c3',
'warga_id': 'warga-005',
'status_penerimaan': 'SUDAHMENERIMA',
'jumlah_bantuan': 1,
'created_at': '2023-01-01',
'warga': {
'id': 'warga-005',
'nama_lengkap': 'Joko Widodo',
'nik': '3201234567890005',
'alamat': 'Jl. Kenanga No. 56, RT 09/RW 10',
'jenis_kelamin': 'L',
'tanggal_lahir': '1965-06-30',
}
}
];
}
// Metode untuk menginisialisasi data penerima penyaluran
void initPenerimaPenyaluran(List<Map<String, dynamic>> data) {
print(
'DEBUG CONTROLLER: Inisialisasi penerima penyaluran dengan ${data.length} item');
// Periksa struktur data
if (data.isNotEmpty) {
final firstItem = data.first;
print(
'DEBUG CONTROLLER: Struktur data penerima: ${firstItem.keys.join(', ')}');
if (firstItem.containsKey('warga')) {
final warga = firstItem['warga'];
print(
'DEBUG CONTROLLER: Struktur data warga: ${warga != null ? (warga is Map ? warga.keys.join(', ') : 'bukan Map') : 'null'}');
} else {
print(
'DEBUG CONTROLLER: Data warga tidak ditemukan dalam item penerima');
}
}
penerimaPenyaluran.value = data;
filteredPenerima.value = data;
jumlahPenerima.value = data.length;
print(
'DEBUG CONTROLLER: Selesai inisialisasi, jumlah penerima: ${jumlahPenerima.value}');
}
// Metode untuk memfilter penerima berdasarkan kata kunci
void filterPenerima(String keyword) {
print('DEBUG CONTROLLER: Memfilter penerima dengan keyword: "$keyword"');
if (keyword.isEmpty) {
print('DEBUG CONTROLLER: Keyword kosong, menerapkan filter status saja');
applyFilters();
return;
}
final lowercaseKeyword = keyword.toLowerCase();
final filtered = penerimaPenyaluran.where((penerima) {
final warga = penerima['warga'] as Map<String, dynamic>?;
if (warga == null) {
print(
'DEBUG CONTROLLER: Data warga null untuk penerima: ${penerima['id']}');
return false;
}
final namaLengkap =
(warga['nama_lengkap'] ?? '').toString().toLowerCase();
final nik = (warga['nik'] ?? '').toString().toLowerCase();
final alamat = (warga['alamat'] ?? '').toString().toLowerCase();
final matches = namaLengkap.contains(lowercaseKeyword) ||
nik.contains(lowercaseKeyword) ||
alamat.contains(lowercaseKeyword);
return matches;
}).toList();
print(
'DEBUG CONTROLLER: Hasil filter: ${filtered.length} dari ${penerimaPenyaluran.length} item');
filteredPenerima.value = filtered;
}
// Metode untuk menerapkan filter status
void applyFilters() {
final keyword = searchPenerimaController.text.toLowerCase();
print(
'DEBUG CONTROLLER: Menerapkan filter dengan status: ${filterStatus.value}, keyword: "$keyword"');
if (filterStatus.value == 'SEMUA' && keyword.isEmpty) {
print('DEBUG CONTROLLER: Tidak ada filter, menampilkan semua data');
filteredPenerima.value = penerimaPenyaluran;
return;
}
final filtered = penerimaPenyaluran.where((penerima) {
bool statusMatch = true;
if (filterStatus.value != 'SEMUA') {
statusMatch = penerima['status_penerimaan'] == filterStatus.value;
}
if (keyword.isEmpty) return statusMatch;
final warga = penerima['warga'] as Map<String, dynamic>?;
if (warga == null) return false;
final namaLengkap =
(warga['nama_lengkap'] ?? '').toString().toLowerCase();
final nik = (warga['nik'] ?? '').toString().toLowerCase();
final alamat = (warga['alamat'] ?? '').toString().toLowerCase();
final keywordMatch = namaLengkap.contains(keyword) ||
nik.contains(keyword) ||
alamat.contains(keyword);
return statusMatch && keywordMatch;
}).toList();
print(
'DEBUG CONTROLLER: Hasil filter gabungan: ${filtered.length} dari ${penerimaPenyaluran.length} item');
filteredPenerima.value = filtered;
}
// Metode untuk memperbarui status penerimaan bantuan
Future<bool> updateStatusPenerimaan(int penerimaId, String status,
{DateTime? tanggalPenerimaan,
String? buktiPenerimaan,
String? keterangan}) async {
try {
final result = await _supabaseService.updateStatusPenerimaan(
penerimaId, status,
tanggalPenerimaan: tanggalPenerimaan,
buktiPenerimaan: buktiPenerimaan,
keterangan: keterangan);
return result;
} catch (e) {
print('Error updating status penerimaan: $e');
return false;
}
}
// Metode untuk menyelesaikan jadwal penyaluran
Future<void> completeJadwal(String jadwalId) async {
try {
await _supabaseService.completeJadwal(jadwalId);
} catch (e) {
print('Error completing jadwal: $e');
throw e.toString();
}
}
// Metode untuk mengubah tab aktif
void changeTab(int index) {
activeTabIndex.value = index;
@ -251,4 +525,76 @@ class PetugasDesaController extends GetxController {
Future<void> logout() async {
await _authController.logout();
}
// Metode untuk debugging struktur data jadwal
void debugJadwalData(Map<String, dynamic> jadwal) {
print('DEBUG CONTROLLER: ===== DEBUGGING JADWAL DATA =====');
print('DEBUG CONTROLLER: Keys dalam jadwal: ${jadwal.keys.join(', ')}');
// Periksa ID
final id = jadwal['id'];
print('DEBUG CONTROLLER: ID jadwal: $id (${id.runtimeType})');
// Periksa data lain yang penting
print('DEBUG CONTROLLER: Nama: ${jadwal['nama']}');
print('DEBUG CONTROLLER: Status: ${jadwal['status']}');
print('DEBUG CONTROLLER: Jumlah penerima: ${jadwal['jumlah_penerima']}');
// Periksa apakah ada data yang null
jadwal.forEach((key, value) {
if (value == null) {
print('DEBUG CONTROLLER: Field "$key" bernilai null');
}
});
print('DEBUG CONTROLLER: ===== END DEBUGGING JADWAL DATA =====');
}
// Metode untuk mendapatkan daftar penerima penyaluran
Future<List<Map<String, dynamic>>?> getPenerimaPenyaluran(
String penyaluranId) async {
print(
'DEBUG CONTROLLER: Mengambil data penerima untuk penyaluran ID: $penyaluranId');
// Gunakan data dummy sementara
final dummyData = _createDummyPenerimaPenyaluran();
print(
'DEBUG CONTROLLER: Mengembalikan ${dummyData.length} data dummy penerima');
return dummyData;
}
// Metode untuk memfilter data penerima berdasarkan status dan pencarian
List<Map<String, dynamic>> get filteredPenerimaPenyaluran {
if (penerimaPenyaluran.isEmpty) {
return [];
}
List<Map<String, dynamic>> filtered =
List<Map<String, dynamic>>.from(penerimaPenyaluran);
// Filter berdasarkan status
if (filterStatus.value != 'SEMUA') {
filtered = filtered.where((penerima) {
return penerima['status_penerimaan'] == filterStatus.value;
}).toList();
}
// Filter berdasarkan pencarian
if (searchQuery.value.isNotEmpty) {
final query = searchQuery.value.toLowerCase();
filtered = filtered.where((penerima) {
final warga = penerima['warga'] as Map<String, dynamic>?;
if (warga == null) return false;
final nama = (warga['nama_lengkap'] ?? '').toString().toLowerCase();
final nik = (warga['nik'] ?? '').toString().toLowerCase();
final alamat = (warga['alamat'] ?? '').toString().toLowerCase();
return nama.contains(query) ||
nik.contains(query) ||
alamat.contains(query);
}).toList();
}
return filtered;
}
}

View File

@ -123,7 +123,7 @@ class StokBantuanController extends GetxController {
Get.snackbar(
'Sukses',
'Stok bantuan berhasil ditambahkan',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -132,7 +132,7 @@ class StokBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal menambahkan stok bantuan: $e',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -155,7 +155,7 @@ class StokBantuanController extends GetxController {
Get.snackbar(
'Sukses',
'Stok bantuan berhasil diperbarui',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -164,7 +164,7 @@ class StokBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal memperbarui stok bantuan: $e',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
@ -178,7 +178,7 @@ class StokBantuanController extends GetxController {
Get.snackbar(
'Sukses',
'Stok bantuan berhasil dihapus',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
@ -187,7 +187,7 @@ class StokBantuanController extends GetxController {
Get.snackbar(
'Error',
'Gagal menghapus stok bantuan: $e',
snackPosition: SnackPosition.BOTTOM,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);