Perbarui logika pengambilan data penerima penyaluran di WargaDashboardController dengan menambahkan pengecekan ID pengguna dan logging untuk debugging. Modifikasi tampilan di WargaPenerimaanView dan WargaPengaduanView untuk meningkatkan pengalaman pengguna dengan menambahkan indikator refresh dan memperbaiki layout. Perbarui BantuanCard untuk menampilkan informasi dengan lebih baik dan menambahkan tombol aksi untuk detail. Implementasikan CustomScrollView untuk stabilitas tampilan yang lebih baik.
This commit is contained in:
@ -13,13 +13,26 @@ class WargaPengaduanView extends GetView<WargaDashboardController> {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
// Debug print untuk melihat jumlah item
|
||||
print('DEBUG: Jumlah pengaduan tersedia: ${controller.pengaduan.length}');
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
// Tambahkan delay untuk memastikan refresh indicator terlihat
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
controller.fetchData();
|
||||
},
|
||||
child: controller.pengaduan.isEmpty
|
||||
? _buildEmptyState()
|
||||
: _buildPengaduanList(),
|
||||
? ListView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: [
|
||||
SizedBox(
|
||||
height: Get.height * 0.7,
|
||||
child: _buildEmptyState(),
|
||||
),
|
||||
],
|
||||
)
|
||||
: _buildPengaduanList(context),
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -56,195 +69,414 @@ class WargaPengaduanView extends GetView<WargaDashboardController> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPengaduanList() {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(16),
|
||||
itemCount: controller.pengaduan.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = controller.pengaduan[index];
|
||||
Widget _buildPengaduanList(BuildContext context) {
|
||||
// Log untuk debugging jumlah item
|
||||
print(
|
||||
'DEBUG: Membangun ListView dengan ${controller.pengaduan.length} pengaduan');
|
||||
|
||||
// Tentukan status dan warna berdasarkan status pengaduan
|
||||
Color statusColor;
|
||||
String statusText;
|
||||
// Menggunakan CustomScrollView untuk layout yang lebih stabil
|
||||
return CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
// Pastikan index valid
|
||||
if (index >= controller.pengaduan.length) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
switch (item.status?.toUpperCase()) {
|
||||
case 'MENUNGGU':
|
||||
statusColor = Colors.orange;
|
||||
statusText = 'Menunggu';
|
||||
break;
|
||||
case 'TINDAKAN':
|
||||
statusColor = Colors.blue;
|
||||
statusText = 'Tindakan';
|
||||
break;
|
||||
case 'SELESAI':
|
||||
statusColor = Colors.green;
|
||||
statusText = 'Selesai';
|
||||
break;
|
||||
case 'DITOLAK':
|
||||
statusColor = Colors.red;
|
||||
statusText = 'Ditolak';
|
||||
break;
|
||||
default:
|
||||
statusColor = Colors.grey;
|
||||
statusText = item.status ?? 'Tidak Diketahui';
|
||||
}
|
||||
final item = controller.pengaduan[index];
|
||||
print(
|
||||
'DEBUG: Membangun item pengaduan $index dengan id: ${item.id}');
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 2,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
// Navigasi ke detail pengaduan
|
||||
Get.toNamed('/warga/detail-pengaduan',
|
||||
arguments: {'id': item.id});
|
||||
},
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.judul ?? 'Pengaduan #${index + 1}',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 6,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(
|
||||
color: statusColor,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
statusText,
|
||||
style: TextStyle(
|
||||
color: statusColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Informasi penyaluran bantuan
|
||||
if (item.penerimaPenyaluran != null)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade50,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
// Tentukan status dan warna berdasarkan status pengaduan
|
||||
Color statusColor;
|
||||
String statusText;
|
||||
|
||||
switch (item.status?.toUpperCase()) {
|
||||
case 'MENUNGGU':
|
||||
statusColor = Colors.orange;
|
||||
statusText = 'Menunggu';
|
||||
break;
|
||||
case 'TINDAKAN':
|
||||
statusColor = Colors.blue;
|
||||
statusText = 'Tindakan';
|
||||
break;
|
||||
case 'SELESAI':
|
||||
statusColor = Colors.green;
|
||||
statusText = 'Selesai';
|
||||
break;
|
||||
case 'DITOLAK':
|
||||
statusColor = Colors.red;
|
||||
statusText = 'Ditolak';
|
||||
break;
|
||||
default:
|
||||
statusColor = Colors.grey;
|
||||
statusText = item.status ?? 'Tidak Diketahui';
|
||||
}
|
||||
|
||||
// Menggunakan SizedBox untuk memberikan batas lebar yang jelas
|
||||
return SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Card(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
side: BorderSide(
|
||||
color: statusColor.withOpacity(0.3),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
elevation: 3,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
// Navigasi ke detail pengaduan
|
||||
Get.toNamed('/warga/detail-pengaduan',
|
||||
arguments: {'id': item.id});
|
||||
},
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Penyaluran: ${item.namaPenyaluran}',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
// Header dengan warna sesuai status
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(12),
|
||||
topRight: Radius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.report_problem,
|
||||
color: statusColor,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Flexible(
|
||||
child: Text(
|
||||
item.judul ??
|
||||
'Pengaduan #${index + 1}',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: statusColor,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 6,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(
|
||||
color: statusColor,
|
||||
width: 1.0,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 3,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
_getStatusIcon(item.status),
|
||||
size: 14,
|
||||
color: statusColor,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
statusText,
|
||||
style: TextStyle(
|
||||
color: statusColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Jenis: ${item.jenisBantuan}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey.shade700,
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Informasi penyaluran bantuan jika ada
|
||||
if (item.penerimaPenyaluran != null)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12),
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade50,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: Colors.blue.shade200,
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.volunteer_activism,
|
||||
color: Colors.blue.shade700,
|
||||
size: 18,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Bantuan Terkait',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue.shade800,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius:
|
||||
BorderRadius.circular(8),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Penyaluran: ${item.namaPenyaluran ?? "Tidak tersedia"}',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildInfoItem(
|
||||
'Jenis',
|
||||
item.jenisBantuan ??
|
||||
"Tidak tersedia",
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _buildInfoItem(
|
||||
'Jumlah',
|
||||
item.jumlahBantuan ??
|
||||
"Tidak tersedia",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Deskripsi pengaduan
|
||||
if (item.deskripsi != null &&
|
||||
item.deskripsi!.isNotEmpty)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12),
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade50,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: Colors.grey.shade200,
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Deskripsi Masalah:',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey.shade800,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
item.deskripsi!,
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Informasi tanggal
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade50,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: Colors.grey.shade200,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Dilaporkan pada: ',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.tanggalPengaduan != null
|
||||
? DateTimeHelper.formatDateTime(
|
||||
item.tanggalPengaduan!)
|
||||
: '-',
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade800,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Jumlah: ${item.jumlahBantuan}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Footer dengan tombol aksi
|
||||
Container(
|
||||
width: double.infinity,
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.black12,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16, vertical: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
// Navigasi ke detail pengaduan
|
||||
Get.toNamed('/warga/detail-pengaduan',
|
||||
arguments: {'id': item.id});
|
||||
},
|
||||
icon: const Icon(Icons.visibility),
|
||||
label: const Text('Lihat Detail'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: statusColor,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16, vertical: 8),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
if (item.deskripsi != null && item.deskripsi!.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: Text(
|
||||
item.deskripsi!,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
item.tanggalPengaduan != null
|
||||
? DateTimeHelper.formatDateTime(
|
||||
item.tanggalPengaduan!)
|
||||
: '-',
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(height: 1),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton.icon(
|
||||
onPressed: () {
|
||||
// Navigasi ke detail pengaduan
|
||||
Get.toNamed('/warga/detail-pengaduan',
|
||||
arguments: {'id': item.id});
|
||||
},
|
||||
icon: const Icon(Icons.visibility),
|
||||
label: const Text('Lihat Detail'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: controller.pengaduan.length,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// Helper method untuk mendapatkan icon berdasarkan status
|
||||
IconData _getStatusIcon(String? status) {
|
||||
switch (status?.toUpperCase()) {
|
||||
case 'MENUNGGU':
|
||||
return Icons.hourglass_empty;
|
||||
case 'TINDAKAN':
|
||||
return Icons.engineering;
|
||||
case 'SELESAI':
|
||||
return Icons.check_circle;
|
||||
case 'DITOLAK':
|
||||
return Icons.cancel;
|
||||
default:
|
||||
return Icons.help_outline;
|
||||
}
|
||||
}
|
||||
|
||||
// Widget untuk item informasi
|
||||
Widget _buildInfoItem(String label, String value) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.grey.shade800,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user