Perbarui model dan tampilan untuk mendukung fungsionalitas QR code dalam proses verifikasi penerima. Tambahkan properti qrCodeHash pada PenerimaPenyaluranModel dan implementasikan metode verifikasi QR code di DetailPenyaluranController. Modifikasi tampilan di WargaDetailPenerimaanView dan DetailPenyaluranPage untuk menampilkan QR code dan menambahkan fungsionalitas pemindaian QR code. Perbarui rute aplikasi untuk mendukung navigasi ke halaman pemindaian QR code dan konfirmasi penerima.
This commit is contained in:
@ -85,8 +85,11 @@ class WargaDashboardController extends GetxController {
|
||||
}
|
||||
|
||||
// Fungsi untuk mengambil data penerima penyaluran
|
||||
Future<void> fetchPenerimaPenyaluran() async {
|
||||
Future<List<PenerimaPenyaluranModel>> fetchPenerimaPenyaluran() async {
|
||||
try {
|
||||
// Reset data terlebih dahulu untuk memastikan tidak ada data lama yang tersimpan
|
||||
penerimaPenyaluran.clear();
|
||||
|
||||
// Pertama, cari warga_id berdasarkan user_id
|
||||
final wargaResponse = await _supabaseService.client
|
||||
.from('warga')
|
||||
@ -175,13 +178,21 @@ class WargaDashboardController extends GetxController {
|
||||
penerima.add(model);
|
||||
}
|
||||
|
||||
// Update nilai observable
|
||||
penerimaPenyaluran.assignAll(penerima);
|
||||
|
||||
var diterima =
|
||||
penerima.where((p) => p.statusPenerimaan == 'DITERIMA').length;
|
||||
totalPenyaluranDiterima.value = diterima;
|
||||
|
||||
// Log untuk debugging
|
||||
print(
|
||||
'Berhasil memuat ${penerima.length} data penerimaan untuk warga ID: $wargaId');
|
||||
|
||||
return penerima;
|
||||
} catch (e) {
|
||||
print('Error fetchPenerimaPenyaluran: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import 'package:penyaluran_app/app/data/models/penerima_penyaluran_model.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
import 'package:penyaluran_app/app/widgets/status_badge.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
|
||||
class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
const WargaDetailPenerimaanView({super.key});
|
||||
@ -14,6 +15,11 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
final Map<String, dynamic> args = Get.arguments ?? {};
|
||||
final id = args['id'];
|
||||
|
||||
// Segera muat ulang data penerimaan ketika halaman dibuka
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
controller.fetchPenerimaPenyaluran();
|
||||
});
|
||||
|
||||
if (id == null) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
@ -28,64 +34,67 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
// Konversi id ke string untuk memastikan kompatibilitas dengan model
|
||||
final String penyaluranId = id.toString();
|
||||
|
||||
// Cari data penerimaan berdasarkan ID
|
||||
final PenerimaPenyaluranModel? penyaluran = controller.penerimaPenyaluran
|
||||
.firstWhereOrNull((item) => item.id == penyaluranId);
|
||||
// Gunakan GetBuilder untuk memastikan widget dibangun ulang ketika data berubah
|
||||
return Obx(() {
|
||||
// Cari data penerimaan berdasarkan ID
|
||||
final PenerimaPenyaluranModel? penyaluran = controller.penerimaPenyaluran
|
||||
.firstWhereOrNull((item) => item.id == penyaluranId);
|
||||
|
||||
if (penyaluran == null) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Detail Penerimaan'),
|
||||
),
|
||||
body: const Center(
|
||||
child: Text('Data penerimaan tidak ditemukan'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final bool isDiterima = penyaluran.statusPenerimaan == 'DITERIMA';
|
||||
|
||||
if (penyaluran == null) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Detail Penerimaan'),
|
||||
elevation: 0,
|
||||
backgroundColor: Get.theme.primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
),
|
||||
body: const Center(
|
||||
child: Text('Data penerimaan tidak ditemukan'),
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Get.theme.primaryColor.withOpacity(0.05),
|
||||
Colors.white,
|
||||
],
|
||||
),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeaderSection(penyaluran),
|
||||
const SizedBox(height: 16),
|
||||
_buildDetailSection(penyaluran),
|
||||
const SizedBox(height: 16),
|
||||
_buildLocationSection(penyaluran),
|
||||
const SizedBox(height: 16),
|
||||
if (isDiterima) _buildBuktiPenerimaanSection(penyaluran),
|
||||
if (isDiterima) const SizedBox(height: 16),
|
||||
_buildAdditionalInfoSection(penyaluran),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final bool isDiterima = penyaluran.statusPenerimaan == 'DITERIMA';
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Detail Penerimaan'),
|
||||
elevation: 0,
|
||||
backgroundColor: Get.theme.primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Get.theme.primaryColor.withOpacity(0.05),
|
||||
Colors.white,
|
||||
],
|
||||
),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeaderSection(penyaluran),
|
||||
const SizedBox(height: 16),
|
||||
_buildDetailSection(penyaluran),
|
||||
const SizedBox(height: 16),
|
||||
_buildLocationSection(penyaluran),
|
||||
const SizedBox(height: 16),
|
||||
if (isDiterima) _buildBuktiPenerimaanSection(penyaluran),
|
||||
if (isDiterima) const SizedBox(height: 16),
|
||||
_buildAdditionalInfoSection(penyaluran),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildHeaderSection(PenerimaPenyaluranModel penyaluran) {
|
||||
@ -577,12 +586,96 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
.format(penyaluran.tanggalPenerimaan!)
|
||||
: 'Tidak tersedia',
|
||||
),
|
||||
|
||||
// Tambahkan QR Code untuk verifikasi
|
||||
if (penyaluran.qrCodeHash != null &&
|
||||
penyaluran.qrCodeHash!.isNotEmpty) ...[
|
||||
const Divider(height: 24),
|
||||
_buildQrCodeSection(penyaluran),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Tambahkan widget untuk menampilkan QR Code
|
||||
Widget _buildQrCodeSection(PenerimaPenyaluranModel penyaluran) {
|
||||
// Pastikan menggunakan data terbaru dari model dan cetak ke log untuk debugging
|
||||
final qrData = penyaluran.qrCodeHash ?? 'invalid-qr-code';
|
||||
print('QR Code Hash: $qrData'); // Log untuk debugging
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.qr_code,
|
||||
color: Get.theme.primaryColor,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'QR Code Verifikasi',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Center(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.2),
|
||||
blurRadius: 4,
|
||||
spreadRadius: 1,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Gunakan UniqueKey() untuk memaksa rebuild widget QR code
|
||||
QrImageView(
|
||||
key: UniqueKey(),
|
||||
data: qrData,
|
||||
version: QrVersions.auto,
|
||||
size: 200.0,
|
||||
backgroundColor: Colors.white,
|
||||
errorStateBuilder: (cxt, err) {
|
||||
return const Center(
|
||||
child: Text(
|
||||
"QR Code tidak tersedia",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'Tunjukkan QR Code ini kepada petugas untuk verifikasi penerimaan',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDetailItem({
|
||||
required IconData icon,
|
||||
required String title,
|
||||
|
Reference in New Issue
Block a user