Tambahkan dukungan penyimpanan lokal dan perbaikan manajemen data

- Integrasikan GetStorage untuk menyimpan data counter secara lokal
- Tambahkan metode loadCountersFromStorage di CounterService
- Perbarui model DonaturModel dan StokBantuanModel untuk konsistensi data
- Tambahkan properti lastUpdateTime di controller untuk melacak pembaruan data
- Perbaiki tampilan dengan menambahkan informasi waktu terakhir update
- Optimalkan metode refresh dan update data di berbagai controller
This commit is contained in:
Khafidh Fuadi
2025-03-12 15:21:16 +07:00
parent d97c324ac9
commit add585fe23
12 changed files with 882 additions and 448 deletions

View File

@ -1,9 +1,21 @@
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
/// Service untuk berbagi data counter antar controller
class CounterService extends GetxService {
static CounterService get to => Get.find<CounterService>();
// Penyimpanan lokal
final GetStorage _storage = GetStorage();
// Keys untuk penyimpanan
static const String _keyMenunggu = 'counter_menunggu';
static const String _keyTerverifikasi = 'counter_terverifikasi';
static const String _keyDitolak = 'counter_ditolak';
static const String _keyDiproses = 'counter_diproses';
static const String _keyNotifikasi = 'counter_notifikasi';
static const String _keyJadwal = 'counter_jadwal';
// Counter untuk penitipan
final RxInt jumlahMenunggu = 0.obs;
final RxInt jumlahTerverifikasi = 0.obs;
@ -18,6 +30,26 @@ class CounterService extends GetxService {
// Counter untuk jadwal
final RxInt jumlahJadwalHariIni = 0.obs;
@override
void onInit() {
super.onInit();
// Muat nilai counter dari penyimpanan lokal
loadCountersFromStorage();
}
// Metode untuk memuat counter dari penyimpanan lokal
void loadCountersFromStorage() {
jumlahMenunggu.value = _storage.read(_keyMenunggu) ?? 0;
jumlahTerverifikasi.value = _storage.read(_keyTerverifikasi) ?? 0;
jumlahDitolak.value = _storage.read(_keyDitolak) ?? 0;
jumlahDiproses.value = _storage.read(_keyDiproses) ?? 0;
jumlahNotifikasiBelumDibaca.value = _storage.read(_keyNotifikasi) ?? 0;
jumlahJadwalHariIni.value = _storage.read(_keyJadwal) ?? 0;
print(
'Counter loaded from storage - Menunggu: ${jumlahMenunggu.value}, Terverifikasi: ${jumlahTerverifikasi.value}, Ditolak: ${jumlahDitolak.value}');
}
// Metode untuk memperbarui counter penitipan
void updatePenitipanCounters({
required int menunggu,
@ -27,20 +59,31 @@ class CounterService extends GetxService {
jumlahMenunggu.value = menunggu;
jumlahTerverifikasi.value = terverifikasi;
jumlahDitolak.value = ditolak;
// Simpan ke penyimpanan lokal
_storage.write(_keyMenunggu, menunggu);
_storage.write(_keyTerverifikasi, terverifikasi);
_storage.write(_keyDitolak, ditolak);
print(
'Counter updated and saved - Menunggu: $menunggu, Terverifikasi: $terverifikasi, Ditolak: $ditolak');
}
// Metode untuk memperbarui counter pengaduan
void updatePengaduanCounter(int diproses) {
jumlahDiproses.value = diproses;
_storage.write(_keyDiproses, diproses);
}
// Metode untuk memperbarui counter notifikasi
void updateNotifikasiCounter(int belumDibaca) {
jumlahNotifikasiBelumDibaca.value = belumDibaca;
_storage.write(_keyNotifikasi, belumDibaca);
}
// Metode untuk memperbarui counter jadwal
void updateJadwalCounter(int hariIni) {
jumlahJadwalHariIni.value = hariIni;
_storage.write(_keyJadwal, hariIni);
}
}

View File

@ -50,6 +50,9 @@ class PenitipanBantuanController extends GetxController {
// Controller untuk pencarian
final TextEditingController searchController = TextEditingController();
// Tambahkan properti untuk waktu terakhir update
Rx<DateTime> lastUpdateTime = DateTime.now().obs;
UserModel? get user => _authController.user;
// Getter untuk counter dari CounterService
@ -75,6 +78,13 @@ class PenitipanBantuanController extends GetxController {
});
}
@override
void onReady() {
super.onReady();
// Pastikan counter diperbarui saat tab diakses kembali
updateCounters();
}
@override
void onClose() {
searchController.dispose();
@ -82,6 +92,13 @@ class PenitipanBantuanController extends GetxController {
super.onClose();
}
// Metode untuk memperbarui data saat tab diakses kembali
void onTabReactivated() {
print('Penitipan tab reactivated - refreshing data');
// Selalu muat ulang data dari server saat tab diaktifkan kembali
refreshData();
}
Future<void> loadPenitipanData() async {
isLoading.value = true;
try {
@ -92,20 +109,7 @@ class PenitipanBantuanController extends GetxController {
.toList();
// Hitung jumlah berdasarkan status
int menunggu =
daftarPenitipan.where((item) => item.status == 'MENUNGGU').length;
int terverifikasi = daftarPenitipan
.where((item) => item.status == 'TERVERIFIKASI')
.length;
int ditolak =
daftarPenitipan.where((item) => item.status == 'DITOLAK').length;
// Update counter di CounterService
_counterService.updatePenitipanCounters(
menunggu: menunggu,
terverifikasi: terverifikasi,
ditolak: ditolak,
);
updateCounters();
// Muat informasi petugas desa untuk item yang terverifikasi
print(
@ -130,6 +134,9 @@ class PenitipanBantuanController extends GetxController {
petugasDesaCache.forEach((key, value) {
print('ID: $key, Nama: ${value['name']}');
});
// Update waktu terakhir refresh
lastUpdateTime.value = DateTime.now();
}
} catch (e) {
print('Error loading penitipan data: $e');
@ -268,6 +275,9 @@ class PenitipanBantuanController extends GetxController {
fotoBantuanPaths.clear();
await loadPenitipanData();
// Pastikan counter diperbarui setelah penambahan
updateCounters();
Get.back(); // Tutup dialog
Get.snackbar(
'Sukses',
@ -313,6 +323,9 @@ class PenitipanBantuanController extends GetxController {
fotoBuktiSerahTerimaPath.value = null;
await loadPenitipanData();
// Pastikan counter diperbarui setelah verifikasi
updateCounters();
Get.back(); // Tutup dialog
Get.snackbar(
'Sukses',
@ -341,6 +354,9 @@ class PenitipanBantuanController extends GetxController {
try {
await _supabaseService.tolakPenitipan(penitipanId, alasan);
await loadPenitipanData();
// Pastikan counter diperbarui setelah penolakan
updateCounters();
Get.snackbar(
'Sukses',
'Penitipan berhasil ditolak',
@ -414,7 +430,10 @@ class PenitipanBantuanController extends GetxController {
Future<void> refreshData() async {
await loadPenitipanData();
await loadKategoriBantuanData();
await loadStokBantuanData();
// Update waktu terakhir refresh
lastUpdateTime.value = DateTime.now();
}
void changeCategory(int index) {
@ -615,16 +634,19 @@ class PenitipanBantuanController extends GetxController {
Future<String?> tambahDonatur({
required String nama,
required String noHp,
required String telepon,
String? alamat,
String? email,
String? jenis,
}) async {
try {
final donaturData = {
'nama': nama,
'no_hp': noHp,
'telepon': telepon,
'alamat': alamat,
'email': email,
'jenis': jenis,
'status': 'AKTIF',
'created_at': DateTime.now().toIso8601String(),
'updated_at': DateTime.now().toIso8601String(),
};
@ -650,4 +672,25 @@ class PenitipanBantuanController extends GetxController {
}
return stokBantuanMap[stokBantuanId]?.isUang ?? false;
}
// Metode baru untuk memperbarui counter
void updateCounters() {
int menunggu =
daftarPenitipan.where((item) => item.status == 'MENUNGGU').length;
int terverifikasi =
daftarPenitipan.where((item) => item.status == 'TERVERIFIKASI').length;
int ditolak =
daftarPenitipan.where((item) => item.status == 'DITOLAK').length;
// Update counter di CounterService
_counterService.updatePenitipanCounters(
menunggu: menunggu,
terverifikasi: terverifikasi,
ditolak: ditolak,
);
// Debug counter values
print(
'Counter updated - Menunggu: $menunggu, Terverifikasi: $terverifikasi, Ditolak: $ditolak');
}
}

View File

@ -5,6 +5,8 @@ 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/modules/petugas_desa/controllers/counter_service.dart';
import 'package:penyaluran_app/app/services/supabase_service.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/penitipan_bantuan_controller.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/stok_bantuan_controller.dart';
class PetugasDesaController extends GetxController {
final AuthController _authController = Get.find<AuthController>();
@ -220,10 +222,28 @@ class PetugasDesaController extends GetxController {
// Jika tab penitipan dipilih, muat ulang data penitipan
if (index == 2) {
loadPenitipanData();
// Dapatkan instance PenitipanBantuanController dan panggil onTabReactivated
try {
final penitipanController = Get.find<PenitipanBantuanController>();
penitipanController.onTabReactivated();
print('Memanggil onTabReactivated pada PenitipanBantuanController');
} catch (e) {
print('Error saat memanggil onTabReactivated: $e');
// Fallback ke metode lama jika controller tidak ditemukan
loadPenitipanData();
}
} else if (index == 3) {
// Jika tab pengaduan dipilih, muat ulang data pengaduan
loadPengaduanData();
} else if (index == 4) {
// Jika tab stok bantuan dipilih, muat ulang data stok bantuan
try {
final stokBantuanController = Get.find<StokBantuanController>();
stokBantuanController.onTabReactivated();
print('Memanggil onTabReactivated pada StokBantuanController');
} catch (e) {
print('Error saat memanggil onTabReactivated: $e');
}
}
}

View File

@ -33,6 +33,9 @@ class StokBantuanController extends GetxController {
// Tambahkan properti untuk total dana bantuan
RxDouble totalDanaBantuan = 0.0.obs;
// Tambahkan properti untuk waktu terakhir update
Rx<DateTime> lastUpdateTime = DateTime.now().obs;
UserModel? get user => _authController.user;
@override
@ -54,6 +57,12 @@ class StokBantuanController extends GetxController {
super.onClose();
}
// Metode untuk memperbarui data saat tab diaktifkan kembali
void onTabReactivated() {
print('Stok Bantuan tab reactivated - refreshing data');
refreshData();
}
Future<void> loadStokBantuanData() async {
isLoading.value = true;
try {
@ -65,6 +74,9 @@ class StokBantuanController extends GetxController {
// Hitung total dana bantuan
_hitungTotalDanaBantuan();
// Update waktu terakhir refresh
lastUpdateTime.value = DateTime.now();
}
} catch (e) {
print('Error loading stok bantuan data: $e');
@ -79,65 +91,14 @@ class StokBantuanController extends GetxController {
await _supabaseService.getPenitipanBantuanTerverifikasi();
if (penitipanData != null) {
daftarPenitipanTerverifikasi.value = penitipanData;
// Update total stok berdasarkan penitipan terverifikasi
_hitungTotalStokDariPenitipan();
// Tidak perlu lagi menghitung total stok dari penitipan
// karena total_stok sudah dikelola oleh trigger database
}
} catch (e) {
print('Error loading penitipan terverifikasi: $e');
}
}
// Metode untuk menghitung total stok dari penitipan terverifikasi
void _hitungTotalStokDariPenitipan() {
// Buat map untuk menyimpan total stok per stok_bantuan_id
Map<String, double> totalStokMap = {};
// Hitung total stok dari penitipan terverifikasi
for (var penitipan in daftarPenitipanTerverifikasi) {
String? stokBantuanId = penitipan['stok_bantuan_id'];
double jumlah = penitipan['jumlah'] != null
? (penitipan['jumlah'] is int
? penitipan['jumlah'].toDouble()
: penitipan['jumlah'])
: 0.0;
if (stokBantuanId != null) {
if (totalStokMap.containsKey(stokBantuanId)) {
totalStokMap[stokBantuanId] =
(totalStokMap[stokBantuanId] ?? 0) + jumlah;
} else {
totalStokMap[stokBantuanId] = jumlah;
}
}
}
// Update total stok di daftarStokBantuan
for (var i = 0; i < daftarStokBantuan.length; i++) {
var stok = daftarStokBantuan[i];
if (stok.id != null) {
// Buat stok baru dengan total stok yang diperbarui
double newTotalStok = totalStokMap[stok.id] ?? 0.0;
daftarStokBantuan[i] = StokBantuanModel(
id: stok.id,
nama: stok.nama,
kategoriBantuanId: stok.kategoriBantuanId,
kategoriBantuan: stok.kategoriBantuan,
totalStok:
newTotalStok, // Gunakan nilai dari penitipan atau 0 jika tidak ada
satuan: stok.satuan,
deskripsi: stok.deskripsi,
createdAt: stok.createdAt,
updatedAt: stok.updatedAt,
isUang: stok.isUang,
);
}
}
// Hitung ulang total dana bantuan
_hitungTotalDanaBantuan();
}
Future<void> loadKategoriBantuanData() async {
try {
final kategoriBantuanData = await _supabaseService.getKategoriBantuan();
@ -151,17 +112,14 @@ class StokBantuanController extends GetxController {
Future<void> addStok(StokBantuanModel stok) async {
try {
// Buat data stok baru tanpa field total_stok
// Buat data stok baru
final stokData = stok.toJson();
// Hapus field total_stok dari data yang akan dikirim ke database
if (stokData.containsKey('total_stok')) {
stokData.remove('total_stok');
}
// Tambahkan total_stok = 0 untuk stok baru
stokData['total_stok'] = 0.0;
await _supabaseService.addStok(stokData);
await loadStokBantuanData();
await loadPenitipanTerverifikasi();
Get.snackbar(
'Sukses',
'Stok bantuan berhasil ditambahkan',
@ -187,13 +145,13 @@ class StokBantuanController extends GetxController {
final stokData = stok.toJson();
// Hapus field total_stok dari data yang akan dikirim ke database
// karena total_stok dikelola oleh trigger database
if (stokData.containsKey('total_stok')) {
stokData.remove('total_stok');
}
await _supabaseService.updateStok(stok.id ?? '', stokData);
await loadStokBantuanData();
await loadPenitipanTerverifikasi();
Get.snackbar(
'Sukses',
'Stok bantuan berhasil diperbarui',
@ -217,7 +175,6 @@ class StokBantuanController extends GetxController {
try {
await _supabaseService.deleteStok(id);
await loadStokBantuanData(); // Ini akan memanggil _hitungTotalDanaBantuan()
await loadPenitipanTerverifikasi(); // Perbarui data penitipan terverifikasi
Get.snackbar(
'Sukses',
'Stok bantuan berhasil dihapus',
@ -241,6 +198,10 @@ class StokBantuanController extends GetxController {
isLoading.value = true;
await loadStokBantuanData();
await loadPenitipanTerverifikasi();
// Update waktu terakhir refresh
lastUpdateTime.value = DateTime.now();
isLoading.value = false;
}
@ -306,14 +267,6 @@ class StokBantuanController extends GetxController {
totalDanaBantuan.value = total;
}
Future<void> _hitungTotalStok() async {
// Implementasi metode _hitungTotalStok
}
Future<void> _filterStokBantuan() async {
// Implementasi metode _filterStokBantuan
}
// Metode untuk mengatur filter
void setFilter(String value) {
filterValue.value = value;