Tambahkan fitur daftar penerima dan navigasi detail penerima

- Buat kontroler dan tampilan untuk daftar penerima
- Tambahkan rute baru untuk daftar penerima dan detail penerima
- Perbarui dashboard dengan navigasi ke daftar penerima
- Tambahkan kemampuan untuk membuka detail penerima dari dashboard
- Integrasikan fitur baru ke dalam drawer navigasi Petugas Desa
This commit is contained in:
Khafidh Fuadi
2025-03-09 09:03:19 +07:00
parent 9d728de946
commit 2dc531af41
9 changed files with 991 additions and 28 deletions

View File

@ -0,0 +1,12 @@
import 'package:get/get.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/penerima_controller.dart';
class PenerimaBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<PenerimaController>(
() => PenerimaController(),
fenix: true,
);
}
}

View File

@ -1,5 +1,6 @@
import 'package:get/get.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/petugas_desa_controller.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/penerima_controller.dart';
class PetugasDesaBinding extends Bindings {
@override
@ -8,5 +9,8 @@ class PetugasDesaBinding extends Bindings {
() => PetugasDesaController(),
fenix: true,
);
Get.lazyPut<PenerimaController>(
() => PenerimaController(),
);
}
}

View File

@ -0,0 +1,152 @@
import 'package:get/get.dart';
class PenerimaController extends GetxController {
final RxList<Map<String, dynamic>> daftarPenerima =
<Map<String, dynamic>>[].obs;
final RxBool isLoading = false.obs;
@override
void onInit() {
super.onInit();
fetchDaftarPenerima();
}
@override
void onReady() {
super.onReady();
// Pastikan data dimuat saat controller siap
if (daftarPenerima.isEmpty) {
fetchDaftarPenerima();
}
}
void fetchDaftarPenerima() {
isLoading.value = true;
// Simulasi data penerima
Future.delayed(const Duration(milliseconds: 500), () {
daftarPenerima.value = [
{
'id': '1',
'nama': 'Bagus Jayadi',
'nik': '3201020107030010',
'noKK': '3201020107030383',
'noHandphone': '089891256532',
'email': 'bgjayadi@gmail.com',
'jenisKelamin': 'Pria',
'agama': 'Islam',
'tempatTanggalLahir': 'Bogor, 2 Juni 1990',
'alamatLengkap':
'Jl. Leada Natsir No. 22 RT 001/003 Kec. Gunung Putri Kab. Bogor',
'pekerjaan': 'Petani',
'pendidikanTerakhir': 'Sekolah Dasar (SD)',
'status': 'Belum disalurkan',
'foto': 'assets/images/profile.jpg',
'terverifikasi': true,
},
{
'id': '2',
'nama': 'Siti Rahayu',
'nik': '3201020107030011',
'noKK': '3201020107030384',
'noHandphone': '089891256533',
'email': 'sitirahayu@gmail.com',
'jenisKelamin': 'Wanita',
'agama': 'Islam',
'tempatTanggalLahir': 'Bogor, 15 Agustus 1985',
'alamatLengkap':
'Jl. Raya Bogor No. 45 RT 002/004 Kec. Gunung Putri Kab. Bogor',
'pekerjaan': 'Ibu Rumah Tangga',
'pendidikanTerakhir': 'SMP',
'status': 'Selesai',
'foto': 'assets/images/profile.jpg',
'terverifikasi': true,
},
{
'id': '3',
'nama': 'Budi Santoso',
'nik': '3201020107030012',
'noKK': '3201020107030385',
'noHandphone': '089891256534',
'email': 'budisantoso@gmail.com',
'jenisKelamin': 'Pria',
'agama': 'Islam',
'tempatTanggalLahir': 'Jakarta, 10 Januari 1980',
'alamatLengkap':
'Jl. Merdeka No. 12 RT 003/005 Kec. Gunung Putri Kab. Bogor',
'pekerjaan': 'Buruh',
'pendidikanTerakhir': 'SMA',
'status': 'Selesai',
'foto': 'assets/images/profile.jpg',
'terverifikasi': true,
},
{
'id': '4',
'nama': 'Dewi Lestari',
'nik': '3201020107030013',
'noKK': '3201020107030386',
'noHandphone': '089891256535',
'email': 'dewilestari@gmail.com',
'jenisKelamin': 'Wanita',
'agama': 'Islam',
'tempatTanggalLahir': 'Bandung, 5 Mei 1992',
'alamatLengkap':
'Jl. Pahlawan No. 8 RT 004/006 Kec. Gunung Putri Kab. Bogor',
'pekerjaan': 'Guru',
'pendidikanTerakhir': 'S1',
'status': 'Selesai',
'foto': 'assets/images/profile.jpg',
'terverifikasi': true,
},
{
'id': '5',
'nama': 'Ahmad Fauzi',
'nik': '3201020107030014',
'noKK': '3201020107030387',
'noHandphone': '089891256536',
'email': 'ahmadfauzi@gmail.com',
'jenisKelamin': 'Pria',
'agama': 'Islam',
'tempatTanggalLahir': 'Surabaya, 20 Desember 1988',
'alamatLengkap':
'Jl. Sudirman No. 15 RT 005/007 Kec. Gunung Putri Kab. Bogor',
'pekerjaan': 'Wiraswasta',
'pendidikanTerakhir': 'SMA',
'status': 'Terjadwal',
'foto': 'assets/images/profile.jpg',
'terverifikasi': true,
},
];
isLoading.value = false;
});
}
Map<String, dynamic>? getPenerimaById(String id) {
try {
if (daftarPenerima.isEmpty) {
// Jika data belum dimuat, muat data terlebih dahulu
fetchDaftarPenerima();
// Kembalikan data dummy sementara
return {
'id': id,
'nama': 'Memuat data...',
'nik': 'Memuat...',
'noKK': 'Memuat...',
'noHandphone': 'Memuat...',
'email': 'Memuat...',
'jenisKelamin': 'Memuat...',
'agama': 'Memuat...',
'tempatTanggalLahir': 'Memuat...',
'alamatLengkap': 'Memuat...',
'pekerjaan': 'Memuat...',
'pendidikanTerakhir': 'Memuat...',
'status': 'Memuat...',
'terverifikasi': false,
};
}
return daftarPenerima.firstWhere((penerima) => penerima['id'] == id);
} catch (e) {
return null;
}
}
}

View File

@ -0,0 +1,316 @@
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/theme/app_theme.dart';
class DaftarPenerimaView extends GetView<PenerimaController> {
const DaftarPenerimaView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Daftar Penerima'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: () {
// Implementasi pencarian
showSearch(
context: context,
delegate: PenerimaSearchDelegate(controller.daftarPenerima),
);
},
),
],
),
body: Obx(() {
if (controller.isLoading.value) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (controller.daftarPenerima.isEmpty) {
return const Center(
child: Text('Tidak ada data penerima'),
);
}
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: controller.daftarPenerima.length,
itemBuilder: (context, index) {
final penerima = controller.daftarPenerima[index];
return _buildPenerimaCard(context, penerima);
},
);
}),
);
}
Widget _buildPenerimaCard(
BuildContext context, Map<String, dynamic> penerima) {
return Card(
margin: const EdgeInsets.only(bottom: 16),
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: InkWell(
onTap: () {
// Navigasi ke halaman detail penerima
Get.toNamed('/daftar-penerima/detail', arguments: penerima['id']);
},
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
// Foto profil
CircleAvatar(
radius: 30,
backgroundColor: AppTheme.primaryColor.withOpacity(0.1),
child: penerima['foto'] != null
? ClipRRect(
borderRadius: BorderRadius.circular(30),
child: Image.asset(
penerima['foto'],
width: 60,
height: 60,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return const Icon(
Icons.person,
size: 30,
color: AppTheme.primaryColor,
);
},
),
)
: const Icon(
Icons.person,
size: 30,
color: AppTheme.primaryColor,
),
),
const SizedBox(width: 16),
// Informasi penerima
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
penerima['nama'] ?? '',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
if (penerima['terverifikasi'] == true)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: Colors.green.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.verified,
size: 14,
color: Colors.green,
),
const SizedBox(width: 4),
const Text(
'Terverifikasi',
style: TextStyle(
fontSize: 12,
color: Colors.green,
),
),
],
),
),
],
),
const SizedBox(height: 4),
Text(
'NIK: ${penerima['nik'] ?? ''}',
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
// const SizedBox(height: 8),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// penerima['alamatLengkap'] ?? '',
// style: TextStyle(
// fontSize: 12,
// color: Colors.grey[600],
// ),
// maxLines: 1,
// overflow: TextOverflow.ellipsis,
// ),
// _buildStatusBadge(penerima['status']),
// ],
// ),
],
),
),
],
),
),
),
);
}
Widget _buildStatusBadge(String? status) {
Color backgroundColor;
Color textColor;
switch (status) {
case 'Selesai':
backgroundColor = Colors.green.withOpacity(0.1);
textColor = Colors.green;
break;
case 'Terjadwal':
backgroundColor = Colors.blue.withOpacity(0.1);
textColor = Colors.blue;
break;
case 'Belum disalurkan':
backgroundColor = Colors.orange.withOpacity(0.1);
textColor = Colors.orange;
break;
default:
backgroundColor = Colors.grey.withOpacity(0.1);
textColor = Colors.grey;
}
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(12),
),
child: Text(
status ?? 'Tidak diketahui',
style: TextStyle(
fontSize: 12,
color: textColor,
),
),
);
}
}
class PenerimaSearchDelegate extends SearchDelegate {
final List<Map<String, dynamic>> daftarPenerima;
PenerimaSearchDelegate(this.daftarPenerima);
@override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
query = '';
},
),
];
}
@override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
close(context, null);
},
);
}
@override
Widget buildResults(BuildContext context) {
return _buildSearchResults();
}
@override
Widget buildSuggestions(BuildContext context) {
return _buildSearchResults();
}
Widget _buildSearchResults() {
final filteredList = daftarPenerima.where((penerima) {
final nama = penerima['nama']?.toString().toLowerCase() ?? '';
final nik = penerima['nik']?.toString().toLowerCase() ?? '';
final alamat = penerima['alamatLengkap']?.toString().toLowerCase() ?? '';
final searchLower = query.toLowerCase();
return nama.contains(searchLower) ||
nik.contains(searchLower) ||
alamat.contains(searchLower);
}).toList();
if (filteredList.isEmpty) {
return const Center(
child: Text('Tidak ada hasil yang ditemukan'),
);
}
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: filteredList.length,
itemBuilder: (context, index) {
final penerima = filteredList[index];
return Card(
margin: const EdgeInsets.only(bottom: 16),
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: ListTile(
onTap: () {
close(context, null);
Get.toNamed('/daftar-penerima/detail', arguments: penerima['id']);
},
leading: CircleAvatar(
backgroundColor: AppTheme.primaryColor.withOpacity(0.1),
child: const Icon(
Icons.person,
color: AppTheme.primaryColor,
),
),
title: Text(
penerima['nama'] ?? '',
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: Text('NIK: ${penerima['nik'] ?? ''}'),
trailing: penerima['terverifikasi'] == true
? const Icon(
Icons.verified,
color: Colors.green,
)
: null,
),
);
},
);
}
}

View File

@ -4,6 +4,7 @@ import 'package:penyaluran_app/app/modules/petugas_desa/components/greeting_head
import 'package:penyaluran_app/app/modules/petugas_desa/components/progress_section.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/components/schedule_card.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/petugas_desa_controller.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/penerima_controller.dart';
import 'package:penyaluran_app/app/theme/app_theme.dart';
import 'package:penyaluran_app/app/widgets/statistic_card.dart';
@ -114,7 +115,9 @@ class DashboardView extends GetView<PetugasDesaController> {
),
),
TextButton(
onPressed: () {},
onPressed: () {
Get.toNamed('/daftar-penerima');
},
child: Row(
children: [
Text(
@ -135,11 +138,11 @@ class DashboardView extends GetView<PetugasDesaController> {
),
const SizedBox(height: 10),
_buildRecipientItem(
'Siti Rahayu', '3201020107030010', 'Selesai', textTheme),
'Siti Rahayu', '3201020107030011', 'Selesai', textTheme),
_buildRecipientItem(
'Budi Santoso', '3201020107030011', 'Selesai', textTheme),
'Budi Santoso', '3201020107030012', 'Selesai', textTheme),
_buildRecipientItem(
'Dewi Lestari', '3201020107030012', 'Selesai', textTheme),
'Dewi Lestari', '3201020107030013', 'Selesai', textTheme),
],
);
}
@ -153,31 +156,45 @@ class DashboardView extends GetView<PetugasDesaController> {
gradient: AppTheme.primaryGradient,
borderRadius: BorderRadius.circular(12),
),
child: ListTile(
title: Text(
name,
style: textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
subtitle: Text(
'NIK: $nik',
style: textTheme.bodyMedium?.copyWith(
color: Colors.white,
),
),
trailing: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: Text(
status,
style: textTheme.bodySmall?.copyWith(
child: InkWell(
onTap: () {
// Navigasi ke detail penerima dengan ID statis
// Kita gunakan ID 1 untuk Siti Rahayu, 2 untuk Budi Santoso, 3 untuk Dewi Lestari
String id = "1"; // Default
if (nik == "3201020107030011") {
id = "2";
} else if (nik == "3201020107030012") {
id = "3";
}
Get.toNamed('/daftar-penerima/detail', arguments: id);
},
borderRadius: BorderRadius.circular(12),
child: ListTile(
title: Text(
name,
style: textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 12,
),
),
subtitle: Text(
'NIK: $nik',
style: textTheme.bodyMedium?.copyWith(
color: Colors.white,
),
),
trailing: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: Text(
status,
style: textTheme.bodySmall?.copyWith(
color: Colors.white,
fontSize: 12,
),
),
),
),

View File

@ -0,0 +1,434 @@
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/theme/app_theme.dart';
class DetailPenerimaView extends GetView<PenerimaController> {
const DetailPenerimaView({super.key});
@override
Widget build(BuildContext context) {
final String id = Get.arguments as String;
return Obx(() {
if (controller.isLoading.value) {
return Scaffold(
appBar: AppBar(
title: const Text('Detail Penerima'),
),
body: const Center(
child: CircularProgressIndicator(),
),
);
}
final penerima = controller.getPenerimaById(id);
if (penerima == null) {
return Scaffold(
appBar: AppBar(
title: const Text('Detail Penerima'),
),
body: const Center(
child: Text('Data penerima tidak ditemukan'),
),
);
}
return Scaffold(
appBar: AppBar(
title: const Text('Detail Penerima'),
actions: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {
// Implementasi edit penerima
},
),
],
),
body: SingleChildScrollView(
child: Column(
children: [
// Header dengan foto dan nama
_buildHeader(penerima),
// Detail informasi penerima
_buildDetailInfo(penerima),
// Status penyaluran
_buildStatusSection(penerima),
const SizedBox(height: 20),
],
),
),
bottomNavigationBar: _buildBottomButtons(penerima),
);
});
}
Widget _buildHeader(Map<String, dynamic> penerima) {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: AppTheme.primaryGradient,
),
child: Column(
children: [
// Foto profil
CircleAvatar(
radius: 50,
backgroundColor: Colors.white,
child: penerima['foto'] != null
? ClipRRect(
borderRadius: BorderRadius.circular(50),
child: Image.asset(
penerima['foto'],
width: 100,
height: 100,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return const Icon(
Icons.person,
size: 50,
color: AppTheme.primaryColor,
);
},
),
)
: const Icon(
Icons.person,
size: 50,
color: AppTheme.primaryColor,
),
),
const SizedBox(height: 16),
// Nama penerima
Text(
penerima['nama'] ?? '',
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 8),
// NIK
Text(
penerima['nik'] ?? '',
style: TextStyle(
fontSize: 16,
color: Colors.white.withOpacity(0.8),
),
),
const SizedBox(height: 16),
// Badge terverifikasi
if (penerima['terverifikasi'] == true)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(20),
),
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.verified,
size: 16,
color: Colors.white,
),
SizedBox(width: 8),
Text(
'Terverifikasi',
style: TextStyle(
fontSize: 14,
color: Colors.white,
),
),
],
),
),
],
),
);
}
Widget _buildDetailInfo(Map<String, dynamic> penerima) {
return Container(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Detail Penerima',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
// Informasi detail dalam bentuk card
Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_buildInfoRow('NIK', penerima['nik'] ?? '-'),
const Divider(),
_buildInfoRow('No KK', penerima['noKK'] ?? '-'),
const Divider(),
_buildInfoRow('No Handphone', penerima['noHandphone'] ?? '-'),
const Divider(),
_buildInfoRow('Email', penerima['email'] ?? '-'),
const Divider(),
_buildInfoRow(
'Jenis Kelamin', penerima['jenisKelamin'] ?? '-'),
const Divider(),
_buildInfoRow('Agama', penerima['agama'] ?? '-'),
const Divider(),
_buildInfoRow('Tempat, Tanggal Lahir',
penerima['tempatTanggalLahir'] ?? '-'),
const Divider(),
_buildInfoRow(
'Alamat Lengkap', penerima['alamatLengkap'] ?? '-'),
const Divider(),
_buildInfoRow('Pekerjaan', penerima['pekerjaan'] ?? '-'),
const Divider(),
_buildInfoRow('Pendidikan Terakhir',
penerima['pendidikanTerakhir'] ?? '-'),
],
),
),
),
],
),
);
}
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 150,
child: Text(
label,
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
),
Expanded(
child: Text(
value,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
),
],
),
);
}
Widget _buildStatusSection(Map<String, dynamic> penerima) {
Color statusColor;
IconData statusIcon;
switch (penerima['status']) {
case 'Selesai':
statusColor = Colors.green;
statusIcon = Icons.check_circle;
break;
case 'Terjadwal':
statusColor = Colors.blue;
statusIcon = Icons.event;
break;
case 'Belum disalurkan':
statusColor = Colors.orange;
statusIcon = Icons.pending;
break;
default:
statusColor = Colors.grey;
statusIcon = Icons.help;
}
return Container(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Status Penyaluran',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: statusColor.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(
statusIcon,
color: statusColor,
size: 24,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
penerima['status'] ?? 'Tidak diketahui',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: statusColor,
),
),
if (penerima['status'] == 'Belum disalurkan')
const Text(
'Penerima ini belum dijadwalkan penyaluran bantuan',
style: TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
if (penerima['status'] == 'Terjadwal')
const Text(
'Penerima ini sudah dijadwalkan penyaluran bantuan',
style: TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
if (penerima['status'] == 'Selesai')
const Text(
'Penerima ini sudah menerima bantuan',
style: TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
],
),
),
],
),
),
),
],
),
);
}
Widget _buildBottomButtons(Map<String, dynamic> penerima) {
// Jika status sudah selesai, tidak perlu menampilkan tombol
if (penerima['status'] == 'Selesai') {
return Container(
padding: const EdgeInsets.all(16),
child: ElevatedButton.icon(
onPressed: () {
// Implementasi lihat riwayat penyaluran
},
icon: const Icon(Icons.history),
label: const Text('Lihat Riwayat Penyaluran'),
style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.primaryColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
);
}
// Jika status belum disalurkan, tampilkan tombol jadwalkan
if (penerima['status'] == 'Belum disalurkan') {
return Container(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: () {
// Implementasi jadwalkan penyaluran
},
icon: const Icon(Icons.event),
label: const Text('Jadwalkan Penyaluran'),
style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.primaryColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
),
],
),
);
}
// Jika status terjadwal, tampilkan tombol konfirmasi penyaluran
return Container(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: () {
// Implementasi konfirmasi penyaluran
},
icon: const Icon(Icons.check_circle),
label: const Text('Konfirmasi Penyaluran'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
),
],
),
);
}
}

View File

@ -1,6 +1,8 @@
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/modules/petugas_desa/controllers/penerima_controller.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/daftar_penerima_view.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/dashboard_view.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/penyaluran_view.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/notifikasi_view.dart';
@ -334,6 +336,14 @@ class PetugasDesaView extends GetView<PetugasDesaController> {
},
)),
const Divider(),
ListTile(
leading: const Icon(Icons.people_outline),
title: const Text('Daftar Penerima'),
onTap: () {
Navigator.pop(context); // Tutup drawer terlebih dahulu
Get.toNamed('/daftar-penerima');
},
),
ListTile(
leading: Stack(
alignment: Alignment.center,

View File

@ -10,6 +10,10 @@ import 'package:penyaluran_app/app/modules/dashboard/bindings/dashboard_binding.
import 'package:penyaluran_app/app/modules/petugas_desa/views/petugas_desa_view.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/bindings/petugas_desa_binding.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/permintaan_penjadwalan_view.dart';
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/controllers/penerima_controller.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/bindings/penerima_binding.dart';
part 'app_routes.dart';
@ -54,5 +58,15 @@ class AppPages {
page: () => const PermintaanPenjadwalanView(),
binding: PetugasDesaBinding(),
),
GetPage(
name: _Paths.daftarPenerima,
page: () => const DaftarPenerimaView(),
binding: PenerimaBinding(),
),
GetPage(
name: _Paths.detailPenerima,
page: () => const DetailPenerimaView(),
binding: PenerimaBinding(),
),
];
}

View File

@ -11,6 +11,8 @@ abstract class Routes {
static const donaturDashboard = _Paths.donaturDashboard;
static const splash = _Paths.splash;
static const permintaanPenjadwalan = _Paths.permintaanPenjadwalan;
static const daftarPenerima = _Paths.daftarPenerima;
static const detailPenerima = _Paths.detailPenerima;
}
abstract class _Paths {
@ -24,4 +26,6 @@ abstract class _Paths {
static const donaturDashboard = '/donatur-dashboard';
static const splash = '/splash';
static const permintaanPenjadwalan = '/permintaan-penjadwalan';
static const daftarPenerima = '/daftar-penerima';
static const detailPenerima = '/daftar-penerima/detail';
}