diff --git a/lib/app/modules/petugas_desa/bindings/penerima_binding.dart b/lib/app/modules/petugas_desa/bindings/penerima_binding.dart new file mode 100644 index 0000000..73bedcb --- /dev/null +++ b/lib/app/modules/petugas_desa/bindings/penerima_binding.dart @@ -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(), + fenix: true, + ); + } +} diff --git a/lib/app/modules/petugas_desa/bindings/petugas_desa_binding.dart b/lib/app/modules/petugas_desa/bindings/petugas_desa_binding.dart index 4f4950e..e840850 100644 --- a/lib/app/modules/petugas_desa/bindings/petugas_desa_binding.dart +++ b/lib/app/modules/petugas_desa/bindings/petugas_desa_binding.dart @@ -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(), + ); } } diff --git a/lib/app/modules/petugas_desa/controllers/penerima_controller.dart b/lib/app/modules/petugas_desa/controllers/penerima_controller.dart new file mode 100644 index 0000000..c110878 --- /dev/null +++ b/lib/app/modules/petugas_desa/controllers/penerima_controller.dart @@ -0,0 +1,152 @@ +import 'package:get/get.dart'; + +class PenerimaController extends GetxController { + final RxList> daftarPenerima = + >[].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? 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; + } + } +} diff --git a/lib/app/modules/petugas_desa/views/daftar_penerima_view.dart b/lib/app/modules/petugas_desa/views/daftar_penerima_view.dart new file mode 100644 index 0000000..4c9ff32 --- /dev/null +++ b/lib/app/modules/petugas_desa/views/daftar_penerima_view.dart @@ -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 { + 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 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> daftarPenerima; + + PenerimaSearchDelegate(this.daftarPenerima); + + @override + List 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, + ), + ); + }, + ); + } +} diff --git a/lib/app/modules/petugas_desa/views/dashboard_view.dart b/lib/app/modules/petugas_desa/views/dashboard_view.dart index 4775585..21283cc 100644 --- a/lib/app/modules/petugas_desa/views/dashboard_view.dart +++ b/lib/app/modules/petugas_desa/views/dashboard_view.dart @@ -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 { ), ), TextButton( - onPressed: () {}, + onPressed: () { + Get.toNamed('/daftar-penerima'); + }, child: Row( children: [ Text( @@ -135,11 +138,11 @@ class DashboardView extends GetView { ), 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 { 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, + ), ), ), ), diff --git a/lib/app/modules/petugas_desa/views/detail_penerima_view.dart b/lib/app/modules/petugas_desa/views/detail_penerima_view.dart new file mode 100644 index 0000000..7c3c56b --- /dev/null +++ b/lib/app/modules/petugas_desa/views/detail_penerima_view.dart @@ -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 { + 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 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 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 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 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), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/app/modules/petugas_desa/views/petugas_desa_view.dart b/lib/app/modules/petugas_desa/views/petugas_desa_view.dart index 55edd00..62e2291 100644 --- a/lib/app/modules/petugas_desa/views/petugas_desa_view.dart +++ b/lib/app/modules/petugas_desa/views/petugas_desa_view.dart @@ -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 { }, )), 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, diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index e097034..5317048 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -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(), + ), ]; } diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart index e2aece7..e40077f 100644 --- a/lib/app/routes/app_routes.dart +++ b/lib/app/routes/app_routes.dart @@ -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'; }