Perbarui JadwalSectionWidget dan KonfirmasiPenerimaView untuk menyederhanakan pengiriman data. Hapus konversi model ke Map dan hanya kirim ID penyaluran. Modifikasi tampilan KonfirmasiPenerimaView untuk menggunakan data dari arguments dan memperbarui logika tampilan penerima. Hapus tampilan PelaksanaanPenyaluranView yang tidak digunakan dan perbarui rute aplikasi untuk mencerminkan perubahan ini.
This commit is contained in:
@ -0,0 +1,11 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/pelaksanaan_penyaluran_controller.dart';
|
||||
|
||||
class PelaksanaanPenyaluranBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut<PelaksanaanPenyaluranController>(
|
||||
() => PelaksanaanPenyaluranController(),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penyaluran_bantuan_model.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/jadwal_penyaluran_controller.dart';
|
||||
import 'package:penyaluran_app/app/routes/app_pages.dart';
|
||||
@ -204,24 +203,8 @@ class JadwalSectionWidget extends StatelessWidget {
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
onTap: () {
|
||||
// Konversi PenyaluranBantuanModel ke Map<String, dynamic>
|
||||
final jadwalMap = {
|
||||
'id': jadwal.id,
|
||||
'nama': jadwal.nama,
|
||||
'deskripsi': jadwal.deskripsi,
|
||||
'lokasi': jadwal.nama, // Gunakan nama sebagai lokasi
|
||||
'kategori_bantuan': jadwal.kategoriBantuanId,
|
||||
'tanggal': jadwal.tanggalPenyaluran != null
|
||||
? DateTimeHelper.formatDate(jadwal.tanggalPenyaluran)
|
||||
: '-',
|
||||
'waktu': jadwal.tanggalPenyaluran != null
|
||||
? DateTimeHelper.formatTime(jadwal.tanggalPenyaluran)
|
||||
: '-',
|
||||
'jumlah_penerima': jadwal.jumlahPenerima,
|
||||
'status': jadwal.status,
|
||||
};
|
||||
|
||||
Get.toNamed(Routes.pelaksanaanPenyaluran, arguments: jadwalMap);
|
||||
// Hanya kirim ID penyaluran
|
||||
Get.toNamed(Routes.pelaksanaanPenyaluran, arguments: jadwal.id);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
@ -336,25 +319,9 @@ class JadwalSectionWidget extends StatelessWidget {
|
||||
alignment: Alignment.centerRight,
|
||||
child: TextButton.icon(
|
||||
onPressed: () {
|
||||
// Konversi PenyaluranBantuanModel ke Map<String, dynamic>
|
||||
final jadwalMap = {
|
||||
'id': jadwal.id,
|
||||
'nama': jadwal.nama,
|
||||
'deskripsi': jadwal.deskripsi,
|
||||
'lokasi': jadwal.nama, // Gunakan nama sebagai lokasi
|
||||
'kategori_bantuan': jadwal.kategoriBantuanId,
|
||||
'tanggal': jadwal.tanggalPenyaluran != null
|
||||
? DateTimeHelper.formatDate(jadwal.tanggalPenyaluran)
|
||||
: '-',
|
||||
'waktu': jadwal.tanggalPenyaluran != null
|
||||
? DateTimeHelper.formatTime(jadwal.tanggalPenyaluran)
|
||||
: '-',
|
||||
'jumlah_penerima': jadwal.jumlahPenerima,
|
||||
'status': jadwal.status,
|
||||
};
|
||||
|
||||
// Hanya kirim ID penyaluran
|
||||
Get.toNamed(Routes.pelaksanaanPenyaluran,
|
||||
arguments: jadwalMap);
|
||||
arguments: jadwal.id);
|
||||
},
|
||||
icon: const Icon(Icons.info_outline, size: 16),
|
||||
label: const Text('Lihat Detail'),
|
||||
|
@ -219,8 +219,6 @@ class PetugasDesaController extends GetxController {
|
||||
|
||||
// Update counter
|
||||
_counterService.updatePengaduanCounter(diproses);
|
||||
|
||||
print('Jumlah pengaduan diproses: $diproses');
|
||||
} else {
|
||||
_counterService.updatePengaduanCounter(0);
|
||||
}
|
||||
|
@ -1,14 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/penerima_controller.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/pelaksanaan_penyaluran_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
|
||||
class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
class KonfirmasiPenerimaView extends GetView<PelaksanaanPenyaluranController> {
|
||||
const KonfirmasiPenerimaView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final String id = Get.arguments as String;
|
||||
// Ambil data dari arguments
|
||||
final Map<String, dynamic> args = Get.arguments ?? {};
|
||||
|
||||
// Pastikan semua parameter yang diperlukan tersedia
|
||||
final penerimaId = args['penerima_id'] ?? 0;
|
||||
final String penyaluranId = args['penyaluran_id']?.toString() ?? '';
|
||||
final Map<String, dynamic> warga =
|
||||
args['warga'] as Map<String, dynamic>? ?? {};
|
||||
final Map<String, dynamic> jadwal =
|
||||
args['jadwal'] as Map<String, dynamic>? ?? {};
|
||||
final String statusPenerimaan =
|
||||
args['status_penerimaan']?.toString() ?? 'BELUMMENERIMA';
|
||||
final dynamic jumlahBantuan = args['jumlah_bantuan'] ?? 1;
|
||||
|
||||
return Obx(() {
|
||||
if (controller.isLoading.value) {
|
||||
@ -22,19 +34,6 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
);
|
||||
}
|
||||
|
||||
final penerima = controller.getPenerimaById(id);
|
||||
|
||||
if (penerima == null) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Konfirmasi Penerima'),
|
||||
),
|
||||
body: const Center(
|
||||
child: Text('Data penerima tidak ditemukan'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Konfirmasi Penerima'),
|
||||
@ -47,27 +46,28 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
child: Column(
|
||||
children: [
|
||||
// Header dengan foto dan nama
|
||||
_buildHeader(penerima),
|
||||
_buildHeader(warga),
|
||||
|
||||
// Detail informasi penerima
|
||||
_buildDetailInfo(penerima),
|
||||
_buildDetailInfo(warga),
|
||||
|
||||
// Detail jadwal dan bantuan
|
||||
_buildDetailJadwalBantuan(penerima),
|
||||
_buildDetailJadwalBantuan(jadwal, jumlahBantuan),
|
||||
|
||||
// Form konfirmasi
|
||||
_buildKonfirmasiForm(context, penerima),
|
||||
_buildKonfirmasiForm(context, penerimaId, penyaluranId),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: _buildBottomButtons(penerima),
|
||||
bottomNavigationBar:
|
||||
_buildBottomButtons(penerimaId, penyaluranId, statusPenerimaan),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildHeader(Map<String, dynamic> penerima) {
|
||||
Widget _buildHeader(Map<String, dynamic> warga) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
@ -80,11 +80,11 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
CircleAvatar(
|
||||
radius: 40,
|
||||
backgroundColor: Colors.white,
|
||||
child: penerima['foto'] != null
|
||||
child: warga['foto_url'] != null
|
||||
? ClipRRect(
|
||||
borderRadius: BorderRadius.circular(40),
|
||||
child: Image.asset(
|
||||
penerima['foto'],
|
||||
child: Image.network(
|
||||
warga['foto_url'],
|
||||
width: 80,
|
||||
height: 80,
|
||||
fit: BoxFit.cover,
|
||||
@ -106,7 +106,7 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
const SizedBox(height: 12),
|
||||
// Nama penerima
|
||||
Text(
|
||||
penerima['nama'] ?? 'Nama tidak tersedia',
|
||||
warga['nama'] ?? 'Nama tidak tersedia',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
@ -116,7 +116,7 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
const SizedBox(height: 4),
|
||||
// NIK
|
||||
Text(
|
||||
penerima['nik'] ?? 'NIK tidak tersedia',
|
||||
warga['nik'] ?? 'NIK tidak tersedia',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.white,
|
||||
@ -127,24 +127,23 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: penerima['status'] == 'Terjadwal'
|
||||
? AppTheme.scheduledColor
|
||||
: AppTheme.completedColor,
|
||||
color: controller.getStatusColor(
|
||||
warga['status_penerimaan'] ?? 'BELUMMENERIMA'),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
penerima['status'] == 'Terjadwal'
|
||||
? Icons.event_available
|
||||
: Icons.check_circle,
|
||||
controller.getStatusIcon(
|
||||
warga['status_penerimaan'] ?? 'BELUMMENERIMA'),
|
||||
color: Colors.white,
|
||||
size: 16,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
penerima['status'] ?? 'Status tidak tersedia',
|
||||
controller.getStatusText(
|
||||
warga['status_penerimaan'] ?? 'BELUMMENERIMA'),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
@ -159,7 +158,7 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDetailInfo(Map<String, dynamic> penerima) {
|
||||
Widget _buildDetailInfo(Map<String, dynamic> warga) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
@ -182,21 +181,19 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildDetailRow('NIK', penerima['nik'] ?? '-'),
|
||||
_buildDetailRow('No KK', penerima['noKK'] ?? '-'),
|
||||
_buildDetailRow('NIK', warga['nik'] ?? '-'),
|
||||
_buildDetailRow('No KK', warga['no_kk'] ?? '-'),
|
||||
_buildDetailRow('No Handphone', warga['no_hp'] ?? '-'),
|
||||
_buildDetailRow('Email', warga['email'] ?? '-'),
|
||||
_buildDetailRow(
|
||||
'No Handphone', penerima['noHandphone'] ?? '-'),
|
||||
_buildDetailRow('Email', penerima['email'] ?? '-'),
|
||||
_buildDetailRow(
|
||||
'Jenis Kelamin', penerima['jenisKelamin'] ?? '-'),
|
||||
_buildDetailRow('Agama', penerima['agama'] ?? '-'),
|
||||
'Jenis Kelamin', warga['jenis_kelamin'] ?? '-'),
|
||||
_buildDetailRow('Agama', warga['agama'] ?? '-'),
|
||||
_buildDetailRow('Tempat, Tanggal Lahir',
|
||||
penerima['tempatTanggalLahir'] ?? '-'),
|
||||
'${warga['tempat_lahir'] ?? '-'}, ${warga['tanggal_lahir'] ?? '-'}'),
|
||||
_buildDetailRow('Alamat Lengkap', warga['alamat'] ?? '-'),
|
||||
_buildDetailRow('Pekerjaan', warga['pekerjaan'] ?? '-'),
|
||||
_buildDetailRow(
|
||||
'Alamat Lengkap', penerima['alamatLengkap'] ?? '-'),
|
||||
_buildDetailRow('Pekerjaan', penerima['pekerjaan'] ?? '-'),
|
||||
_buildDetailRow('Pendidikan Terakhir',
|
||||
penerima['pendidikanTerakhir'] ?? '-'),
|
||||
'Pendidikan Terakhir', warga['pendidikan'] ?? '-'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -206,17 +203,8 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDetailJadwalBantuan(Map<String, dynamic> penerima) {
|
||||
// Simulasi data jadwal dan bantuan
|
||||
final jadwalBantuan = {
|
||||
'tanggal': '15 Agustus 2023',
|
||||
'waktu': '09:00 - 12:00 WIB',
|
||||
'lokasi': 'Balai Desa Gunung Putri, Jl. Raya Gunung Putri No. 10',
|
||||
'jenisBantuan': 'Bantuan Sosial Tunai (BST)',
|
||||
'nilaiNominal': 'Rp 600.000',
|
||||
'keterangan': 'Bantuan diberikan dalam bentuk tunai'
|
||||
};
|
||||
|
||||
Widget _buildDetailJadwalBantuan(
|
||||
Map<String, dynamic> jadwal, dynamic jumlahBantuan) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
@ -240,15 +228,13 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
child: Column(
|
||||
children: [
|
||||
_buildDetailRow(
|
||||
'Tanggal Penyaluran', jadwalBantuan['tanggal'] ?? '-'),
|
||||
_buildDetailRow('Waktu', jadwalBantuan['waktu'] ?? '-'),
|
||||
_buildDetailRow('Lokasi', jadwalBantuan['lokasi'] ?? '-'),
|
||||
'Tanggal Penyaluran', jadwal['tanggal'] ?? '-'),
|
||||
_buildDetailRow('Waktu', jadwal['waktu'] ?? '-'),
|
||||
_buildDetailRow('Lokasi', jadwal['lokasi'] ?? '-'),
|
||||
_buildDetailRow(
|
||||
'Jenis Bantuan', jadwalBantuan['jenisBantuan'] ?? '-'),
|
||||
_buildDetailRow(
|
||||
'Nilai Nominal', jadwalBantuan['nilaiNominal'] ?? '-'),
|
||||
_buildDetailRow(
|
||||
'Keterangan', jadwalBantuan['keterangan'] ?? '-'),
|
||||
'Jenis Bantuan', jadwal['jenis_bantuan'] ?? '-'),
|
||||
_buildDetailRow('Jumlah Bantuan', '$jumlahBantuan item'),
|
||||
_buildDetailRow('Keterangan', jadwal['keterangan'] ?? '-'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -289,7 +275,7 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
}
|
||||
|
||||
Widget _buildKonfirmasiForm(
|
||||
BuildContext context, Map<String, dynamic> penerima) {
|
||||
BuildContext context, int penerimaId, String penyaluranId) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
@ -470,11 +456,23 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.asset(
|
||||
child: Image.network(
|
||||
controller.fotoBuktiPath.value,
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
color: Colors.grey.shade200,
|
||||
child: const Icon(
|
||||
Icons.broken_image,
|
||||
size: 40,
|
||||
color: Colors.grey,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
@ -545,11 +543,23 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.asset(
|
||||
child: Image.network(
|
||||
controller.tandaTanganPath.value,
|
||||
height: 150,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: 150,
|
||||
width: double.infinity,
|
||||
color: Colors.grey.shade200,
|
||||
child: const Icon(
|
||||
Icons.broken_image,
|
||||
size: 40,
|
||||
color: Colors.grey,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
@ -606,7 +616,10 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBottomButtons(Map<String, dynamic> penerima) {
|
||||
Widget _buildBottomButtons(
|
||||
int penerimaId, String penyaluranId, String statusPenerimaan) {
|
||||
final bool sudahDiterima = statusPenerimaan == 'SUDAHMENERIMA';
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
@ -631,18 +644,22 @@ class KonfirmasiPenerimaView extends GetView<PenerimaController> {
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Obx(() => ElevatedButton(
|
||||
onPressed: controller.isKonfirmasiChecked.value &&
|
||||
onPressed: sudahDiterima
|
||||
? null
|
||||
: (controller.isKonfirmasiChecked.value &&
|
||||
controller.isIdentitasChecked.value &&
|
||||
controller.isDataValidChecked.value &&
|
||||
controller.fotoBuktiPath.value.isNotEmpty &&
|
||||
controller.tandaTanganPath.value.isNotEmpty
|
||||
? () => controller.konfirmasiPenyaluran(penerima['id'])
|
||||
: null,
|
||||
? () => controller.konfirmasiPenyaluran(
|
||||
penerimaId, penyaluranId)
|
||||
: null),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppTheme.primaryColor,
|
||||
disabledBackgroundColor: Colors.grey.shade300,
|
||||
),
|
||||
child: const Text('Konfirmasi'),
|
||||
child:
|
||||
Text(sudahDiterima ? 'Sudah Dikonfirmasi' : 'Konfirmasi'),
|
||||
)),
|
||||
),
|
||||
],
|
||||
|
@ -1,878 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/petugas_desa_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
|
||||
class PelaksanaanPenyaluranView extends GetView<PetugasDesaController> {
|
||||
const PelaksanaanPenyaluranView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Ambil data jadwal dari parameter
|
||||
final jadwal = Get.arguments as Map<String, dynamic>;
|
||||
|
||||
// Debug: Tampilkan data jadwal yang diterima
|
||||
print('DEBUG: Jadwal yang diterima: $jadwal');
|
||||
print('DEBUG: ID Jadwal: ${jadwal['id']}');
|
||||
|
||||
// Debug: Periksa koneksi ke Supabase menggunakan instance dari controller
|
||||
try {
|
||||
controller.supabaseService.client
|
||||
.from('penyaluran_bantuan')
|
||||
.select('id')
|
||||
.limit(1)
|
||||
.then((_) {
|
||||
print('DEBUG: Koneksi ke Supabase berhasil');
|
||||
}).catchError((error) {
|
||||
print('DEBUG: Koneksi ke Supabase gagal: $error');
|
||||
});
|
||||
} catch (e) {
|
||||
print('DEBUG: Error saat memeriksa koneksi Supabase: $e');
|
||||
}
|
||||
|
||||
// Debug: Periksa struktur data jadwal
|
||||
controller.debugJadwalData(jadwal);
|
||||
|
||||
// Muat data penerima saat halaman dimuat
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
controller.reloadPenerimaPenyaluran();
|
||||
});
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Pelaksanaan Penyaluran'),
|
||||
// actions: [
|
||||
// // Tombol debug untuk melihat SQL query
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.code),
|
||||
// onPressed: () {
|
||||
// final penyaluranId = Get.parameters['id'] ?? jadwal['id'];
|
||||
// _showSqlDebugDialog(context, penyaluranId);
|
||||
// },
|
||||
// tooltip: 'Lihat SQL Query',
|
||||
// ),
|
||||
// ],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Informasi jadwal
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
margin: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withAlpha(26),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 3,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeaderInfo(context, jadwal),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Daftar penerima bantuan
|
||||
_buildDaftarPenerima(context, jadwal),
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: _buildBottomButtons(context, jadwal),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeaderInfo(BuildContext context, Map<String, dynamic> jadwal) {
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
jadwal['lokasi'] ?? 'Lokasi Penyaluran',
|
||||
style: textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildInfoItem(
|
||||
context,
|
||||
icon: Icons.category,
|
||||
label: 'Jenis Bantuan',
|
||||
value: jadwal['jenis_bantuan'] ?? 'Tidak tersedia',
|
||||
),
|
||||
_buildInfoItem(
|
||||
context,
|
||||
icon: Icons.calendar_today,
|
||||
label: 'Tanggal',
|
||||
value: jadwal['tanggal'] ?? 'Tidak tersedia',
|
||||
),
|
||||
_buildInfoItem(
|
||||
context,
|
||||
icon: Icons.access_time,
|
||||
label: 'Waktu',
|
||||
value: jadwal['waktu'] ?? 'Tidak tersedia',
|
||||
),
|
||||
_buildInfoItem(
|
||||
context,
|
||||
icon: Icons.people,
|
||||
label: 'Jumlah Penerima',
|
||||
value: '${controller.jumlahPenerima} orang',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoItem(
|
||||
BuildContext context, {
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required String value,
|
||||
bool isStatus = false,
|
||||
}) {
|
||||
final bool isActive = isStatus && value.toUpperCase() == 'AKTIF';
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 18,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'$label: ',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
if (isStatus)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: isActive ? Colors.green[50] : Colors.orange[50],
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
color: isActive ? Colors.green : Colors.orange,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDaftarPenerima(
|
||||
BuildContext context, Map<String, dynamic> jadwal) {
|
||||
// Debug: Periksa validitas ID penyaluran
|
||||
final penyaluranId = jadwal['id'];
|
||||
if (penyaluranId == null || penyaluranId.toString().isEmpty) {
|
||||
print('DEBUG: PERINGATAN! ID penyaluran kosong atau null: $penyaluranId');
|
||||
|
||||
// Tampilkan pesan error jika ID tidak valid
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
const Icon(Icons.error_outline, color: Colors.red, size: 48),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'ID penyaluran tidak valid: $penyaluranId',
|
||||
style: TextStyle(color: Colors.red),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Daftar Penerima Bantuan',
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Obx(() => Text(
|
||||
'${controller.jumlahPenerima.value} orang',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Search bar
|
||||
TextField(
|
||||
controller: controller.searchPenerimaController,
|
||||
onChanged: (value) => controller.filterPenerima(value),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Cari penerima...',
|
||||
prefixIcon: const Icon(Icons.search),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade50,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Filter status
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: [
|
||||
_buildFilterChip(
|
||||
context, 'Semua', controller.filterStatus.value == 'SEMUA'),
|
||||
const SizedBox(width: 8),
|
||||
_buildFilterChip(context, 'Sudah Diterima',
|
||||
controller.filterStatus.value == 'SUDAHMENERIMA'),
|
||||
const SizedBox(width: 8),
|
||||
_buildFilterChip(context, 'Belum Diterima',
|
||||
controller.filterStatus.value == 'BELUMMENERIMA'),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Daftar penerima - gunakan SizedBox dengan height tertentu daripada Expanded
|
||||
SizedBox(
|
||||
height: 400, // Tinggi tetap, sesuaikan sesuai kebutuhan
|
||||
child: Obx(() {
|
||||
// Tampilkan loading jika sedang memuat ulang data
|
||||
if (controller.isLoading.value) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
// Tampilkan pesan jika tidak ada data
|
||||
if (controller.filteredPenerimaPenyaluran.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.people_outline,
|
||||
color: Colors.grey,
|
||||
size: 60,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Tidak ada data penerima untuk penyaluran ini',
|
||||
style: TextStyle(fontSize: 16),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
controller.reloadPenerimaPenyaluran();
|
||||
},
|
||||
child: const Text('Refresh Data'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Tampilkan data penerima
|
||||
return ListView.builder(
|
||||
itemCount: controller.filteredPenerimaPenyaluran.length,
|
||||
itemBuilder: (context, index) {
|
||||
final penerima = controller.filteredPenerimaPenyaluran[index];
|
||||
return _buildPenerimaItem(context, penerima);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFilterChip(BuildContext context, String label, bool isSelected) {
|
||||
String statusValue;
|
||||
switch (label) {
|
||||
case 'Sudah Diterima':
|
||||
statusValue = 'SUDAHMENERIMA';
|
||||
break;
|
||||
case 'Belum Diterima':
|
||||
statusValue = 'BELUMMENERIMA';
|
||||
break;
|
||||
default:
|
||||
statusValue = 'SEMUA';
|
||||
}
|
||||
|
||||
return FilterChip(
|
||||
label: Text(label),
|
||||
selected: isSelected,
|
||||
onSelected: (selected) {
|
||||
if (selected) {
|
||||
controller.filterStatus.value = statusValue;
|
||||
controller.applyFilters();
|
||||
}
|
||||
},
|
||||
backgroundColor: Colors.grey.shade100,
|
||||
selectedColor: AppTheme.primaryColor.withOpacity(0.2),
|
||||
checkmarkColor: AppTheme.primaryColor,
|
||||
labelStyle: TextStyle(
|
||||
color: isSelected ? AppTheme.primaryColor : Colors.black,
|
||||
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Metode untuk menampilkan dialog debug
|
||||
void _showDebugDialog(BuildContext context, Map<String, dynamic> data) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Debug Data'),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('Data Struktur:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 8),
|
||||
Text('Keys: ${data.keys.toList().join(', ')}'),
|
||||
const Divider(),
|
||||
if (data.containsKey('warga')) ...[
|
||||
const Text('Warga Data:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 8),
|
||||
if (data['warga'] != null)
|
||||
Text(
|
||||
'Warga Keys: ${(data['warga'] as Map<String, dynamic>).keys.toList().join(', ')}')
|
||||
else
|
||||
const Text('Warga data is null'),
|
||||
const Divider(),
|
||||
],
|
||||
const Text('Raw Data:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 8),
|
||||
Text(data.toString(), style: const TextStyle(fontSize: 12)),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
child: const Text('Tutup'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Metode untuk membangun item penerima dengan tombol debug
|
||||
Widget _buildPenerimaItem(
|
||||
BuildContext context, Map<String, dynamic> penerima) {
|
||||
final bool sudahDiterima = penerima['status_penerimaan'] == 'SUDAHMENERIMA';
|
||||
final warga = penerima['warga'] as Map<String, dynamic>?;
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withAlpha(26),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 3,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
title: Text(
|
||||
warga?['nama_lengkap'] ?? 'Nama tidak tersedia',
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 4),
|
||||
Text('NIK: ${warga?['nik'] ?? 'NIK tidak tersedia'}'),
|
||||
const SizedBox(height: 2),
|
||||
Text('Alamat: ${warga?['alamat'] ?? 'Alamat tidak tersedia'}'),
|
||||
if (penerima['jumlah_bantuan'] != null) ...[
|
||||
const SizedBox(height: 2),
|
||||
Text('Jumlah Bantuan: ${penerima['jumlah_bantuan']}'),
|
||||
],
|
||||
],
|
||||
),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Tombol debug untuk melihat struktur data
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.bug_report, color: Colors.grey),
|
||||
// onPressed: () => _showDebugDialog(context, penerima),
|
||||
// tooltip: 'Lihat struktur data',
|
||||
// iconSize: 20,
|
||||
// ),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: sudahDiterima
|
||||
? Colors.green.withAlpha(26)
|
||||
: Colors.orange.withAlpha(26),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
sudahDiterima ? 'Sudah Diterima' : 'Belum Diterima',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: sudahDiterima ? Colors.green : Colors.orange,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
// Navigasi ke halaman konfirmasi penerima
|
||||
Get.toNamed(
|
||||
'/konfirmasi-penerima',
|
||||
arguments: {
|
||||
'penerima_id': penerima['id'],
|
||||
'penyaluran_id': penerima['penyaluran_bantuan_id'],
|
||||
'warga': warga,
|
||||
'status_penerimaan': penerima['status_penerimaan'],
|
||||
'jumlah_bantuan': penerima['jumlah_bantuan'],
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBottomButtons(
|
||||
BuildContext context, Map<String, dynamic> jadwal) {
|
||||
final String status = (jadwal['status'] ?? '').toUpperCase();
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withAlpha(50),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 5,
|
||||
offset: const Offset(0, -1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// Tampilkan tombol berdasarkan status
|
||||
if (status == 'AKTIF') ...[
|
||||
// Tombol Cetak Laporan
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
Get.snackbar(
|
||||
'Informasi',
|
||||
'Mencetak laporan penyaluran...',
|
||||
snackPosition: SnackPosition.TOP,
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.print),
|
||||
label: const Text('Cetak Laporan'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// Tombol Selesaikan
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
_showSelesaikanDialog(context, jadwal);
|
||||
},
|
||||
icon: const Icon(Icons.check_circle),
|
||||
label: const Text('Selesaikan'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
] else if (status == 'SELESAI') ...[
|
||||
// Hanya tampilkan tombol Cetak Laporan
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
Get.snackbar(
|
||||
'Informasi',
|
||||
'Mencetak laporan penyaluran...',
|
||||
snackPosition: SnackPosition.TOP,
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.print),
|
||||
label: const Text('Cetak Laporan'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
] else if (status == 'DIBATALKAN') ...[
|
||||
// Tampilkan pesan dibatalkan
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red[50],
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Text(
|
||||
'Penyaluran Dibatalkan',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
// Status lainnya - tampilkan pesan default
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[100],
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
'Status: $status',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Colors.grey,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showSelesaikanDialog(
|
||||
BuildContext context, Map<String, dynamic> jadwal) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Selesaikan Penyaluran'),
|
||||
content:
|
||||
const Text('Apakah Anda yakin ingin menyelesaikan penyaluran ini? '
|
||||
'Pastikan semua penerima telah dikonfirmasi.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('Batal'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// Implementasi selesaikan penyaluran
|
||||
controller.completeJadwal(jadwal['id']).then((_) {
|
||||
Navigator.pop(context);
|
||||
Get.back(); // Kembali ke halaman sebelumnya
|
||||
Get.snackbar(
|
||||
'Berhasil',
|
||||
'Penyaluran telah diselesaikan',
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: Colors.green,
|
||||
colorText: Colors.white,
|
||||
);
|
||||
}).catchError((error) {
|
||||
Navigator.pop(context);
|
||||
Get.snackbar(
|
||||
'Gagal',
|
||||
'Terjadi kesalahan: $error',
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
);
|
||||
});
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
child: const Text('Selesaikan'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Metode untuk menampilkan filter dan pencarian
|
||||
Widget _buildFilterAndSearch(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withAlpha(26),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 3,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Filter & Pencarian',
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Filter status
|
||||
Row(
|
||||
children: [
|
||||
const Text('Status: '),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
final currentFilter = controller.filterStatus.value;
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: [
|
||||
// Filter Semua
|
||||
InkWell(
|
||||
onTap: () => controller.filterStatus.value = 'SEMUA',
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: currentFilter == 'SEMUA'
|
||||
? Colors.blue
|
||||
: Colors.grey[200],
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Text(
|
||||
'Semua',
|
||||
style: TextStyle(
|
||||
color: currentFilter == 'SEMUA'
|
||||
? Colors.white
|
||||
: Colors.black87,
|
||||
fontWeight: currentFilter == 'SEMUA'
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
// Filter Sudah Menerima
|
||||
InkWell(
|
||||
onTap: () =>
|
||||
controller.filterStatus.value = 'SUDAHMENERIMA',
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: currentFilter == 'SUDAHMENERIMA'
|
||||
? Colors.blue
|
||||
: Colors.grey[200],
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Text(
|
||||
'Sudah Menerima',
|
||||
style: TextStyle(
|
||||
color: currentFilter == 'SUDAHMENERIMA'
|
||||
? Colors.white
|
||||
: Colors.black87,
|
||||
fontWeight: currentFilter == 'SUDAHMENERIMA'
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
// Filter Belum Menerima
|
||||
InkWell(
|
||||
onTap: () =>
|
||||
controller.filterStatus.value = 'BELUMMENERIMA',
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: currentFilter == 'BELUMMENERIMA'
|
||||
? Colors.blue
|
||||
: Colors.grey[200],
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Text(
|
||||
'Belum Menerima',
|
||||
style: TextStyle(
|
||||
color: currentFilter == 'BELUMMENERIMA'
|
||||
? Colors.white
|
||||
: Colors.black87,
|
||||
fontWeight: currentFilter == 'BELUMMENERIMA'
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Pencarian
|
||||
TextField(
|
||||
onChanged: (value) => controller.searchQuery.value = value,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Cari berdasarkan nama atau NIK',
|
||||
prefixIcon: const Icon(Icons.search),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Metode untuk menampilkan dialog debug SQL
|
||||
void _showSqlDebugDialog(BuildContext context, String penyaluranId) {
|
||||
final validId = controller.ensureValidUUID(penyaluranId);
|
||||
final sqlQuery = '''
|
||||
SELECT
|
||||
penerima_penyaluran.*,
|
||||
warga.*
|
||||
FROM
|
||||
penerima_penyaluran
|
||||
LEFT JOIN
|
||||
warga ON warga.id = penerima_penyaluran.warga_id
|
||||
WHERE
|
||||
penerima_penyaluran.penyaluran_bantuan_id = '$validId';
|
||||
''';
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('SQL Query Debug'),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('SQL Query yang digunakan:'),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[200],
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: SelectableText(
|
||||
sqlQuery,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'monospace',
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text('Petunjuk:'),
|
||||
const SizedBox(height: 8),
|
||||
const Text('1. Salin query ini ke SQL Editor di Supabase'),
|
||||
const Text('2. Jalankan query untuk melihat hasil'),
|
||||
const Text(
|
||||
'3. Bandingkan dengan data yang ditampilkan di aplikasi'),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
child: const Text('Tutup'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -378,10 +378,6 @@ class PetugasDesaView extends GetView<PetugasDesaController> {
|
||||
}
|
||||
|
||||
Widget _buildBottomNavigationBar() {
|
||||
// Tambahkan print statement untuk debugging
|
||||
print('Jumlah pengaduan diproses: ${controller.jumlahDiproses.value}');
|
||||
print('Jumlah jadwal hari ini: ${controller.jadwalHariIni.length}');
|
||||
|
||||
return Obx(() {
|
||||
return BottomNavigationBar(
|
||||
currentIndex: controller.activeTabIndex.value,
|
||||
|
@ -221,13 +221,11 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
selectedSkemaBantuanId.value ?? '')
|
||||
.eq('status', 'TERVERIFIKASI');
|
||||
|
||||
if (pengajuanData != null) {
|
||||
Get.dialog(
|
||||
Dialog(
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width * 0.9,
|
||||
height:
|
||||
MediaQuery.of(context).size.height * 0.8,
|
||||
height: MediaQuery.of(context).size.height * 0.8,
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -268,8 +266,7 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
.asMap()
|
||||
.entries
|
||||
.map((entry) {
|
||||
final warga =
|
||||
entry.value['warga'];
|
||||
final warga = entry.value['warga'];
|
||||
return DataRow(
|
||||
cells: [
|
||||
DataCell(
|
||||
@ -277,8 +274,8 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
DataCell(Text(
|
||||
warga['nama_lengkap'] ??
|
||||
'-')),
|
||||
DataCell(Text(
|
||||
warga['nik'] ?? '-')),
|
||||
DataCell(
|
||||
Text(warga['nik'] ?? '-')),
|
||||
DataCell(Text(
|
||||
warga['alamat'] ?? '-')),
|
||||
],
|
||||
@ -293,7 +290,6 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.people),
|
||||
label: const Text('Lihat Daftar Penerima'),
|
||||
|
@ -7,7 +7,6 @@ import 'package:penyaluran_app/app/modules/petugas_desa/views/permintaan_penjadw
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/daftar_penerima_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/detail_penerima_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/konfirmasi_penerima_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/pelaksanaan_penyaluran_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/riwayat_penitipan_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/daftar_donatur_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/detail_donatur_view.dart';
|
||||
@ -63,11 +62,6 @@ class AppPages {
|
||||
page: () => const KonfirmasiPenerimaView(),
|
||||
binding: PenerimaBinding(),
|
||||
),
|
||||
GetPage(
|
||||
name: _Paths.pelaksanaanPenyaluran,
|
||||
page: () => const PelaksanaanPenyaluranView(),
|
||||
binding: PetugasDesaBinding(),
|
||||
),
|
||||
GetPage(
|
||||
name: _Paths.profile,
|
||||
page: () => const ProfileView(),
|
||||
|
@ -20,6 +20,9 @@ abstract class Routes {
|
||||
static const daftarDonatur = _Paths.daftarDonatur;
|
||||
static const detailDonatur = _Paths.detailDonatur;
|
||||
static const tambahPenyaluran = _Paths.tambahPenyaluran;
|
||||
static const daftarPenerimaPenyaluran = _Paths.daftarPenerimaPenyaluran;
|
||||
static const detailPenerimaPenyaluran = _Paths.detailPenerimaPenyaluran;
|
||||
static const laporanPenyaluran = _Paths.laporanPenyaluran;
|
||||
}
|
||||
|
||||
abstract class _Paths {
|
||||
@ -42,4 +45,7 @@ abstract class _Paths {
|
||||
static const daftarDonatur = '/daftar-donatur';
|
||||
static const detailDonatur = '/daftar-donatur/detail';
|
||||
static const tambahPenyaluran = '/tambah-penyaluran';
|
||||
static const daftarPenerimaPenyaluran = '/daftar-penerima-penyaluran';
|
||||
static const detailPenerimaPenyaluran = '/detail-penerima-penyaluran';
|
||||
static const laporanPenyaluran = '/laporan-penyaluran';
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'dart:io';
|
||||
import 'package:penyaluran_app/app/utils/date_time_helper.dart';
|
||||
|
||||
class SupabaseService extends GetxService {
|
||||
static SupabaseService get to => Get.find<SupabaseService>();
|
||||
|
Reference in New Issue
Block a user