Perbarui model PenerimaPenyaluran untuk menyertakan properti qrCodeHash dan hapus properti yang tidak digunakan. Modifikasi controller DetailPenyaluranController untuk menambahkan fungsi pengambilan data penerima penyaluran berdasarkan ID. Sesuaikan tampilan di halaman konfirmasi penerima dan detail penerimaan untuk meningkatkan pengalaman pengguna. Hapus kode yang tidak diperlukan untuk menjaga kebersihan kode.

This commit is contained in:
Khafidh Fuadi
2025-03-30 18:50:26 +07:00
parent 5aaeb58d2b
commit ba3e71efe7
16 changed files with 1416 additions and 527 deletions

View File

@ -8,22 +8,25 @@ class PenerimaPenyaluranModel {
final String? statusPenerimaan;
final DateTime? tanggalPenerimaan;
final String? buktiPenerimaan;
final String? keterangan;
final double? jumlahBantuan;
final String? stokBantuanId;
final Map<String, dynamic>? warga; // Data warga yang terkait
final String? tandaTangan;
final bool? isUang; // Apakah bantuan berupa uang
final String? satuan; // Satuan bantuan
final String? qrCodeHash;
// Relasi data
final Map<String, dynamic>? warga; // Data warga yang terkait
final Map<String, dynamic>? stokBantuan; // Data stok bantuan
final Map<String, dynamic>? penyaluranBantuan; // Data penyaluran bantuan
final String? kategoriNama; // Nama kategori bantuan
final String? namaPenyaluran; // Nama penyaluran
final String? deskripsiPenyaluran; // Deskripsi penyaluran
final String? lokasiPenyaluranNama; // Nama lokasi penyaluran
final String? lokasiPenyaluranAlamat; // Alamat lokasi penyaluran
final String? qrCodeHash; // Hash untuk QR code
final String? statusPenyaluran; // Status penyaluran
// Properti turunan yang diambil dari relasi
final String? kategoriNama; // Nama kategori bantuan dari relasi
final String? namaPenyaluran; // Nama penyaluran dari relasi
final String? deskripsiPenyaluran; // Deskripsi penyaluran dari relasi
final String? lokasiPenyaluranNama; // Nama lokasi penyaluran dari relasi
final String? lokasiPenyaluranAlamat; // Alamat lokasi penyaluran dari relasi
final String? statusPenyaluran; // Status penyaluran dari relasi
final String? satuan; // Satuan dari relasi stok bantuan
final bool? isUang; // Flag is_uang dari relasi stok bantuan
PenerimaPenyaluranModel({
this.id,
@ -33,22 +36,23 @@ class PenerimaPenyaluranModel {
this.statusPenerimaan,
this.tanggalPenerimaan,
this.buktiPenerimaan,
this.keterangan,
this.jumlahBantuan,
this.stokBantuanId,
this.warga,
this.tandaTangan,
this.isUang,
this.satuan,
this.qrCodeHash,
// Relasi
this.warga,
this.stokBantuan,
this.penyaluranBantuan,
// Properti turunan
this.kategoriNama,
this.namaPenyaluran,
this.deskripsiPenyaluran,
this.lokasiPenyaluranNama,
this.lokasiPenyaluranAlamat,
this.qrCodeHash,
this.statusPenyaluran,
this.satuan,
this.isUang,
});
factory PenerimaPenyaluranModel.fromRawJson(String str) =>
@ -69,22 +73,23 @@ class PenerimaPenyaluranModel {
? DateTime.parse(json["tanggal_penerimaan"])
: null,
buktiPenerimaan: json["bukti_penerimaan"],
keterangan: json["keterangan"],
jumlahBantuan: json["jumlah_bantuan"]?.toDouble(),
stokBantuanId: json["stok_bantuan_id"],
warga: json["warga"],
tandaTangan: json["tanda_tangan"],
isUang: json["is_uang"],
satuan: json["satuan"],
qrCodeHash: json["qr_code_hash"],
// Relasi
warga: json["warga"],
stokBantuan: json["stok_bantuan"],
penyaluranBantuan: json["penyaluran_bantuan"],
// Properti turunan
kategoriNama: json["kategori_nama"],
namaPenyaluran: json["nama_penyaluran"],
deskripsiPenyaluran: json["deskripsi_penyaluran"],
lokasiPenyaluranNama: json["lokasi_penyaluran_nama"],
lokasiPenyaluranAlamat: json["lokasi_penyaluran_alamat"],
qrCodeHash: json["qr_code_hash"],
statusPenyaluran: json["status_penyaluran"],
satuan: json["satuan"] ?? json["stok_bantuan"]?["satuan"],
isUang: json["is_uang"] ?? json["stok_bantuan"]?["is_uang"],
);
Map<String, dynamic> toJson() => {
@ -95,21 +100,11 @@ class PenerimaPenyaluranModel {
"status_penerimaan": statusPenerimaan,
"tanggal_penerimaan": tanggalPenerimaan?.toIso8601String(),
"bukti_penerimaan": buktiPenerimaan,
"keterangan": keterangan,
"jumlah_bantuan": jumlahBantuan,
"stok_bantuan_id": stokBantuanId,
"warga": warga,
"tanda_tangan": tandaTangan,
"is_uang": isUang,
"satuan": satuan,
"stok_bantuan": stokBantuan,
"penyaluran_bantuan": penyaluranBantuan,
"kategori_nama": kategoriNama,
"nama_penyaluran": namaPenyaluran,
"deskripsi_penyaluran": deskripsiPenyaluran,
"lokasi_penyaluran_nama": lokasiPenyaluranNama,
"lokasi_penyaluran_alamat": lokasiPenyaluranAlamat,
"qr_code_hash": qrCodeHash,
"status_penyaluran": statusPenyaluran,
// Relasi tidak perlu disertakan dalam toJson karena
// biasanya hanya digunakan untuk serialisasi ke database
};
}

View File

@ -604,4 +604,59 @@ class DetailPenyaluranController extends GetxController {
isExporting.value = false;
}
}
// Fungsi untuk mengambil data penerima penyaluran berdasarkan ID
Future<PenerimaPenyaluranModel?> getPenerimaPenyaluranById(
String penerimaPenyaluranId) async {
try {
// Ambil data penerima penyaluran dengan relasinya
final data = await _supabaseService.client
.from('penerima_penyaluran')
.select(
'*, warga:warga_id(*), stok_bantuan:stok_bantuan_id(*), penyaluran_bantuan:penyaluran_bantuan_id(*)')
.eq('id', penerimaPenyaluranId)
.single();
// Konversi data ke model
final Map<String, dynamic> sanitizedData =
Map<String, dynamic>.from(data);
// Konversi jumlah_bantuan ke double jika bertipe String
if (sanitizedData['jumlah_bantuan'] is String) {
sanitizedData['jumlah_bantuan'] =
double.tryParse(sanitizedData['jumlah_bantuan'] as String);
}
return PenerimaPenyaluranModel.fromJson(sanitizedData);
} catch (e) {
print('Error mengambil data penerima penyaluran: $e');
Get.snackbar(
'Error',
'Terjadi kesalahan saat mengambil data penerima',
backgroundColor: Colors.red,
colorText: Colors.white,
);
return null;
}
}
// Fungsi untuk memuat penyaluran dengan id tertentu
Future<void> getDetailPenyaluran(String penyaluranId) async {
try {
isLoading.value = true;
// Ambil data penyaluran
await loadPenyaluranData(penyaluranId);
} catch (e) {
print('Error getDetailPenyaluran: $e');
Get.snackbar(
'Error',
'Gagal memuat data detail penyaluran',
backgroundColor: Colors.red,
colorText: Colors.white,
);
} finally {
isLoading.value = false;
}
}
}

View File

@ -376,7 +376,6 @@ class PelaksanaanPenyaluranController extends GetxController {
statusPenerimaan: 'DITERIMA',
tanggalPenerimaan: penerimaPenyaluran[index].tanggalPenerimaan,
buktiPenerimaan: penerimaPenyaluran[index].buktiPenerimaan,
keterangan: penerimaPenyaluran[index].keterangan,
jumlahBantuan: penerimaPenyaluran[index].jumlahBantuan,
stokBantuanId: penerimaPenyaluran[index].stokBantuanId,
warga: penerimaPenyaluran[index].warga,

View File

@ -1406,16 +1406,10 @@ class DetailPenyaluranPage extends StatelessWidget {
void _showKonfirmasiPenerimaan(
BuildContext context, PenerimaPenyaluranModel penerima) {
// Dapatkan data jumlah bantuan dari penerima
final jumlahBantuan = penerima.jumlahBantuan?.toString() ?? '5';
// Navigasi ke halaman konfirmasi penerima
// Navigasi ke halaman konfirmasi penerima dengan hanya mengirimkan ID
Get.to(
() => KonfirmasiPenerimaPage(
penerima: penerima,
bentukBantuan:
null, // Tidak ada data bentuk bantuan yang tersedia langsung
jumlahBantuan: jumlahBantuan,
penerimaPenyaluranId: penerima.id!,
tanggalPenyaluran: controller.penyaluran.value?.tanggalPenyaluran,
),
)?.then((result) {
@ -1778,9 +1772,6 @@ class DetailPenyaluranPage extends StatelessWidget {
if (penerima.jumlahBantuan != null)
_buildInfoRow('Jumlah Bantuan',
penerima.jumlahBantuan.toString()),
if (penerima.keterangan != null &&
penerima.keterangan!.isNotEmpty)
_buildInfoRow('Keterangan', penerima.keterangan!),
],
),
),

View File

@ -158,24 +158,6 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
penyaluran.namaPenyaluran ??
penyaluran.keterangan ??
'Bantuan',
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
],
),
const SizedBox(height: 16),
if (penyaluran.deskripsiPenyaluran != null &&
penyaluran.deskripsiPenyaluran!.isNotEmpty)
Padding(
@ -452,16 +434,6 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
],
),
],
if (penyaluran.keterangan != null &&
penyaluran.keterangan!.isNotEmpty) ...[
const Divider(height: 24),
_buildDetailItem(
icon: Icons.note,
title: 'Keterangan',
value: penyaluran.keterangan!,
statusColor: null,
),
],
],
),
),

View File

@ -207,10 +207,15 @@ class AppPages {
),
GetPage(
name: _Paths.konfirmasiPenerimaQr,
page: () => KonfirmasiPenerimaPage(
penerima: Get.arguments['penerima'],
tanggalPenyaluran: Get.arguments['tanggal_penyaluran'],
),
page: () {
final penerima = Get.arguments['penerima'];
final String penerimaPenyaluranId = penerima?.id ?? '';
return KonfirmasiPenerimaPage(
penerimaPenyaluranId: penerimaPenyaluranId,
tanggalPenyaluran: Get.arguments['tanggal_penyaluran'],
);
},
binding: PenyaluranBinding(),
),
GetPage(

View File

@ -81,16 +81,6 @@ class BantuanCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
item.namaPenyaluran ?? item.keterangan ?? 'Bantuan',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
const SizedBox(height: 6),
Text(
item.kategoriNama ?? 'Bantuan',
style: TextStyle(
@ -245,22 +235,6 @@ class BantuanCard extends StatelessWidget {
? Colors.green.shade700
: Colors.blue.shade700,
),
const SizedBox(width: 8),
Flexible(
child: Text(
item.namaPenyaluran ??
item.keterangan ??
'Bantuan',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: item.isUang == true
? Colors.green.shade800
: Colors.blue.shade800,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
),