Perbarui status dan model penyaluran untuk konsistensi dan fungsionalitas

- Ganti enum StatusKelayakan dari 'pending', 'disetujui', 'ditolak' menjadi 'MENUNGGU', 'TERVERIFIKASI', 'DITOLAK'
- Ubah referensi 'jadwalSelesai' menjadi 'jadwalTerlaksana' di beberapa komponen
- Perbarui ikon dan warna status di JadwalSectionWidget
- Tambahkan logika baru untuk menangani status 'BATALTERLAKSANA' dan 'TERLAKSANA' di JadwalPenyaluranController
- Modifikasi tampilan untuk menampilkan 'Terlaksana' dan 'Jumlah Penerima' secara otomatis di TambahPenyaluranView
- Tambahkan fungsi untuk memuat data skema bantuan dan pengajuan kelayakan yang disetujui
This commit is contained in:
Khafidh Fuadi
2025-03-14 23:17:02 +07:00
parent ecc1ccac59
commit 0e757c0b94
7 changed files with 284 additions and 93 deletions

View File

@ -1,6 +1,6 @@
import 'dart:convert'; import 'dart:convert';
enum StatusKelayakan { pending, disetujui, ditolak } enum StatusKelayakan { MENUNGGU, TERVERIFIKASI, DITOLAK }
class PengajuanKelayakanBantuanModel { class PengajuanKelayakanBantuanModel {
final String? id; final String? id;

View File

@ -245,7 +245,7 @@ class CalendarViewWidget extends StatelessWidget {
List<PenyaluranBantuanModel> allJadwal = [ List<PenyaluranBantuanModel> allJadwal = [
...controller.jadwalHariIni, ...controller.jadwalHariIni,
...controller.jadwalMendatang, ...controller.jadwalMendatang,
...controller.jadwalSelesai, ...controller.jadwalTerlaksana,
]; ];
DateTime now = DateTime.now(); DateTime now = DateTime.now();

View File

@ -92,8 +92,10 @@ class JadwalSectionWidget extends StatelessWidget {
return Icons.event_note; return Icons.event_note;
case 'Terjadwal': case 'Terjadwal':
return Icons.pending_actions; return Icons.pending_actions;
case 'Selesai': case 'Terlaksana':
return Icons.event_available; return Icons.event_available;
case 'Tidak Terlaksana':
return Icons.event_busy;
default: default:
return Icons.event_note; return Icons.event_note;
} }
@ -105,8 +107,9 @@ class JadwalSectionWidget extends StatelessWidget {
return Icons.calendar_today; return Icons.calendar_today;
case 'Terjadwal': case 'Terjadwal':
return Icons.schedule; return Icons.schedule;
case 'Selesai': case 'Terlaksana':
return Icons.task_alt; return Icons.task_alt;
default: default:
return Icons.event_note; return Icons.event_note;
} }
@ -118,7 +121,7 @@ class JadwalSectionWidget extends StatelessWidget {
return Colors.green; return Colors.green;
case 'Terjadwal': case 'Terjadwal':
return Colors.blue; return Colors.blue;
case 'Selesai': case 'Terlaksana':
return Colors.grey; return Colors.grey;
default: default:
return Colors.orange; return Colors.orange;
@ -127,16 +130,18 @@ class JadwalSectionWidget extends StatelessWidget {
String _getStatusText(PenyaluranBantuanModel jadwal) { String _getStatusText(PenyaluranBantuanModel jadwal) {
// Jika status jadwal adalah BERLANGSUNG, tampilkan sebagai "Aktif" // Jika status jadwal adalah BERLANGSUNG, tampilkan sebagai "Aktif"
if (jadwal.status == 'BERLANGSUNG') { if (jadwal.status == 'AKTIF') {
return 'Aktif'; return 'Aktif';
} }
// Jika status jadwal adalah DIJADWALKAN, tampilkan sebagai "Terjadwal" // Jika status jadwal adalah DIJADWALKAN, tampilkan sebagai "Terjadwal"
else if (jadwal.status == 'DIJADWALKAN' || jadwal.status == 'DISETUJUI') { else if (jadwal.status == 'DIJADWALKAN') {
return 'Terjadwal'; return 'Terjadwal';
} }
// Jika status jadwal adalah SELESAI, tampilkan sebagai "Selesai" // Jika status jadwal adalah terlaksana, tampilkan sebagai "Terlaksana"
else if (jadwal.status == 'SELESAI') { else if (jadwal.status == 'TERLAKSANA') {
return 'Selesai'; return 'Terlaksana';
} else if (jadwal.status == 'BATALTERLAKSANA') {
return 'Batal Terlaksana';
} }
// Default status // Default status
return status; return status;
@ -144,16 +149,16 @@ class JadwalSectionWidget extends StatelessWidget {
Color _getStatusColorByJadwal(PenyaluranBantuanModel jadwal) { Color _getStatusColorByJadwal(PenyaluranBantuanModel jadwal) {
// Jika status jadwal adalah BERLANGSUNG, gunakan warna hijau // Jika status jadwal adalah BERLANGSUNG, gunakan warna hijau
if (jadwal.status == 'BERLANGSUNG') { if (jadwal.status == 'AKTIF') {
return Colors.green; return Colors.green;
} }
// Jika status jadwal adalah DIJADWALKAN, gunakan warna biru // Jika status jadwal adalah DIJADWALKAN, gunakan warna biru
else if (jadwal.status == 'DIJADWALKAN' || jadwal.status == 'DISETUJUI') { else if (jadwal.status == 'DIJADWALKAN') {
return Colors.blue; return Colors.blue;
} } else if (jadwal.status == 'TERLAKSANA') {
// Jika status jadwal adalah SELESAI, gunakan warna abu-abu
else if (jadwal.status == 'SELESAI') {
return Colors.grey; return Colors.grey;
} else if (jadwal.status == 'BATALTERLAKSANA') {
return Colors.red;
} }
// Default warna // Default warna
return _getStatusColor(); return _getStatusColor();
@ -165,8 +170,8 @@ class JadwalSectionWidget extends StatelessWidget {
return controller.jadwalHariIni.toList(); return controller.jadwalHariIni.toList();
case 'Mendatang': case 'Mendatang':
return controller.jadwalMendatang.toList(); return controller.jadwalMendatang.toList();
case 'Selesai': case 'Terlaksana':
return controller.jadwalSelesai.toList(); return controller.jadwalTerlaksana.toList();
default: default:
return jadwalList; return jadwalList;
} }

View File

@ -4,6 +4,7 @@ import 'package:penyaluran_app/app/data/models/penyaluran_bantuan_model.dart';
import 'package:penyaluran_app/app/data/models/lokasi_penyaluran_model.dart'; import 'package:penyaluran_app/app/data/models/lokasi_penyaluran_model.dart';
import 'package:penyaluran_app/app/data/models/kategori_bantuan_model.dart'; import 'package:penyaluran_app/app/data/models/kategori_bantuan_model.dart';
import 'package:penyaluran_app/app/data/models/user_model.dart'; import 'package:penyaluran_app/app/data/models/user_model.dart';
import 'package:penyaluran_app/app/data/models/skema_bantuan_model.dart';
import 'package:penyaluran_app/app/modules/auth/controllers/auth_controller.dart'; import 'package:penyaluran_app/app/modules/auth/controllers/auth_controller.dart';
import 'package:penyaluran_app/app/services/supabase_service.dart'; import 'package:penyaluran_app/app/services/supabase_service.dart';
import 'package:penyaluran_app/app/utils/date_time_helper.dart'; import 'package:penyaluran_app/app/utils/date_time_helper.dart';
@ -13,6 +14,8 @@ class JadwalPenyaluranController extends GetxController {
final AuthController _authController = Get.find<AuthController>(); final AuthController _authController = Get.find<AuthController>();
final SupabaseService _supabaseService = SupabaseService.to; final SupabaseService _supabaseService = SupabaseService.to;
SupabaseService get supabaseService => _supabaseService;
final RxBool isLoading = false.obs; final RxBool isLoading = false.obs;
// Indeks kategori yang dipilih untuk filter // Indeks kategori yang dipilih untuk filter
@ -23,7 +26,7 @@ class JadwalPenyaluranController extends GetxController {
<PenyaluranBantuanModel>[].obs; <PenyaluranBantuanModel>[].obs;
final RxList<PenyaluranBantuanModel> jadwalMendatang = final RxList<PenyaluranBantuanModel> jadwalMendatang =
<PenyaluranBantuanModel>[].obs; <PenyaluranBantuanModel>[].obs;
final RxList<PenyaluranBantuanModel> jadwalSelesai = final RxList<PenyaluranBantuanModel> jadwalTerlaksana =
<PenyaluranBantuanModel>[].obs; <PenyaluranBantuanModel>[].obs;
// Data untuk permintaan penjadwalan // Data untuk permintaan penjadwalan
@ -36,6 +39,8 @@ class JadwalPenyaluranController extends GetxController {
<String, LokasiPenyaluranModel>{}.obs; <String, LokasiPenyaluranModel>{}.obs;
final RxMap<String, KategoriBantuanModel> kategoriBantuanCache = final RxMap<String, KategoriBantuanModel> kategoriBantuanCache =
<String, KategoriBantuanModel>{}.obs; <String, KategoriBantuanModel>{}.obs;
final RxMap<String, SkemaBantuanModel> skemaBantuanCache =
<String, SkemaBantuanModel>{}.obs;
// Controller untuk pencarian // Controller untuk pencarian
final TextEditingController searchController = TextEditingController(); final TextEditingController searchController = TextEditingController();
@ -49,6 +54,7 @@ class JadwalPenyaluranController extends GetxController {
loadPermintaanPenjadwalanData(); loadPermintaanPenjadwalanData();
loadLokasiPenyaluranData(); loadLokasiPenyaluranData();
loadKategoriBantuanData(); loadKategoriBantuanData();
loadSkemaBantuanData();
// Jalankan timer untuk memeriksa jadwal secara berkala // Jalankan timer untuk memeriksa jadwal secara berkala
_startJadwalCheckTimer(); _startJadwalCheckTimer();
@ -89,8 +95,9 @@ class JadwalPenyaluranController extends GetxController {
// Periksa jadwal mendatang yang tanggalnya hari ini // Periksa jadwal mendatang yang tanggalnya hari ini
List<PenyaluranBantuanModel> jadwalToUpdate = []; List<PenyaluranBantuanModel> jadwalToUpdate = [];
List<PenyaluranBantuanModel> jadwalTerlewat = [];
for (var jadwal in jadwalMendatang) { for (var jadwal in jadwalHariIni) {
if (jadwal.tanggalPenyaluran != null) { if (jadwal.tanggalPenyaluran != null) {
// Konversi tanggal jadwal ke timezone lokal // Konversi tanggal jadwal ke timezone lokal
final jadwalDateTime = final jadwalDateTime =
@ -103,24 +110,29 @@ class JadwalPenyaluranController extends GetxController {
// Jika tanggal jadwal adalah hari ini // Jika tanggal jadwal adalah hari ini
if (isSameDay(jadwalDate, today)) { if (isSameDay(jadwalDate, today)) {
jadwalToUpdate.add(jadwal);
// Jika waktu jadwal sudah tiba atau lewat // Jika waktu jadwal sudah tiba atau lewat
if (now.isAfter(jadwalDateTime) || if (now.isAfter(jadwalDateTime) ||
now.isAtSameMomentAs(jadwalDateTime)) { now.isAtSameMomentAs(jadwalDateTime)) {
// Ubah status menjadi BERLANGSUNG (aktif) if (jadwal.status == 'DIJADWALKAN') {
// Jika status masih DIJADWALKAN, ubah menjadi BATALTERLAKSANA
await _supabaseService.updateJadwalStatus( await _supabaseService.updateJadwalStatus(
jadwal.id!, 'BERLANGSUNG'); jadwal.id!, 'BATALTERLAKSANA');
jadwalTerlewat.add(jadwal);
} else if (jadwal.status == 'AKTIF') {
// Jika status BERLANGSUNG, tambahkan ke daftar update
jadwalToUpdate.add(jadwal);
}
} }
} }
} }
} }
// Refresh data setelah pembaruan // Refresh data setelah pembaruan
if (jadwalToUpdate.isNotEmpty) { if (jadwalToUpdate.isNotEmpty || jadwalTerlewat.isNotEmpty) {
await loadJadwalData(); await loadJadwalData();
// Tampilkan notifikasi jika ada jadwal yang dipindahkan // Tampilkan notifikasi jika ada jadwal yang dipindahkan
if (jadwalToUpdate.isNotEmpty) {
Get.snackbar( Get.snackbar(
'Jadwal Diperbarui', 'Jadwal Diperbarui',
'${jadwalToUpdate.length} jadwal dipindahkan ke section Hari Ini', '${jadwalToUpdate.length} jadwal dipindahkan ke section Hari Ini',
@ -130,6 +142,19 @@ class JadwalPenyaluranController extends GetxController {
duration: const Duration(seconds: 3), duration: const Duration(seconds: 3),
); );
} }
// Tampilkan notifikasi jika ada jadwal yang terlewat
if (jadwalTerlewat.isNotEmpty) {
Get.snackbar(
'Jadwal Terlewat',
'${jadwalTerlewat.length} jadwal diubah menjadi BATALTERLAKSANA',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.orange,
colorText: Colors.white,
duration: const Duration(seconds: 3),
);
}
}
} catch (e) { } catch (e) {
print('Error checking and updating jadwal status: $e'); print('Error checking and updating jadwal status: $e');
} }
@ -162,9 +187,9 @@ class JadwalPenyaluranController extends GetxController {
} }
// Mengambil data jadwal selesai // Mengambil data jadwal selesai
final jadwalSelesaiData = await _supabaseService.getJadwalSelesai(); final jadwalTerlaksanaData = await _supabaseService.getJadwalTerlaksana();
if (jadwalSelesaiData != null) { if (jadwalTerlaksanaData != null) {
jadwalSelesai.value = jadwalSelesaiData jadwalTerlaksana.value = jadwalTerlaksanaData
.map((data) => PenyaluranBantuanModel.fromJson(data)) .map((data) => PenyaluranBantuanModel.fromJson(data))
.toList(); .toList();
} }
@ -219,6 +244,22 @@ class JadwalPenyaluranController extends GetxController {
} }
} }
Future<void> loadSkemaBantuanData() async {
try {
final skemaData = await _supabaseService.getAllSkemaBantuan();
if (skemaData != null) {
for (var skema in skemaData) {
final skemaModel = SkemaBantuanModel.fromJson(skema);
if (skemaModel.id != null) {
skemaBantuanCache[skemaModel.id!] = skemaModel;
}
}
}
} catch (e) {
print('Error loading skema bantuan data: $e');
}
}
// Mendapatkan nama lokasi penyaluran berdasarkan ID // Mendapatkan nama lokasi penyaluran berdasarkan ID
String getLokasiPenyaluranName(String? lokasiId) { String getLokasiPenyaluranName(String? lokasiId) {
if (lokasiId == null) return 'Lokasi tidak diketahui'; if (lokasiId == null) return 'Lokasi tidak diketahui';
@ -333,7 +374,7 @@ class JadwalPenyaluranController extends GetxController {
Future<void> tambahPenyaluran({ Future<void> tambahPenyaluran({
required String nama, required String nama,
required String deskripsi, required String deskripsi,
required String kategoriBantuanId, required String skemaId,
required String lokasiPenyaluranId, required String lokasiPenyaluranId,
required int jumlahPenerima, required int jumlahPenerima,
required DateTime? tanggalPenyaluran, required DateTime? tanggalPenyaluran,
@ -349,7 +390,7 @@ class JadwalPenyaluranController extends GetxController {
final penyaluran = { final penyaluran = {
'nama': nama, 'nama': nama,
'deskripsi': deskripsi, 'deskripsi': deskripsi,
'kategori_bantuan_id': kategoriBantuanId, 'skema_id': skemaId,
'lokasi_penyaluran_id': lokasiPenyaluranId, 'lokasi_penyaluran_id': lokasiPenyaluranId,
'petugas_id': user!.id, 'petugas_id': user!.id,
'jumlah_penerima': jumlahPenerima, 'jumlah_penerima': jumlahPenerima,
@ -357,8 +398,30 @@ class JadwalPenyaluranController extends GetxController {
'status': 'DIJADWALKAN', // Status awal adalah terjadwal 'status': 'DIJADWALKAN', // Status awal adalah terjadwal
}; };
// Simpan ke database // Simpan ke database dan dapatkan ID penyaluran
await _supabaseService.tambahPenyaluran(penyaluran); final response = await _supabaseService.tambahPenyaluran(penyaluran);
final penyaluranId = response['id'];
// Ambil data pengajuan kelayakan bantuan yang disetujui
final pengajuanData = await _supabaseService.client
.from('xx02_pengajuan_kelayakan_bantuan')
.select('*')
.eq('skema_bantuan_id', skemaId)
.eq('status', 'TERVERIFIKASI');
// Buat data penerima penyaluran untuk setiap pengajuan yang disetujui
for (var pengajuan in pengajuanData) {
final penerimaPenyaluran = {
'penyaluran_bantuan_id': penyaluranId,
'warga_id': pengajuan['warga_id'],
'stok_bantuan_id': skemaBantuanCache[skemaId]?.stokBantuanId,
'status_penerimaan': 'MENUNGGU',
};
await _supabaseService.client
.from('penerima_penyaluran')
.insert(penerimaPenyaluran);
}
// Refresh data // Refresh data
await loadJadwalData(); await loadJadwalData();

View File

@ -101,9 +101,9 @@ class PenyaluranView extends GetView<JadwalPenyaluranController> {
// Jadwal selesai // Jadwal selesai
JadwalSectionWidget( JadwalSectionWidget(
controller: controller, controller: controller,
title: 'Selesai', title: 'Terlaksana',
jadwalList: controller.jadwalSelesai, jadwalList: controller.jadwalTerlaksana,
status: 'Selesai', status: 'Terlaksana',
), ),
], ],
); );
@ -190,9 +190,9 @@ class PenyaluranView extends GetView<JadwalPenyaluranController> {
Expanded( Expanded(
child: Obx(() => _buildSummaryItem( child: Obx(() => _buildSummaryItem(
context, context,
icon: Icons.event_busy, icon: Icons.event_note,
title: 'Selesai', title: 'Terlaksana',
value: '${controller.jadwalSelesai.length}', value: '${controller.jadwalTerlaksana.length}',
color: Colors.grey, color: Colors.grey,
)), )),
), ),

View File

@ -3,6 +3,8 @@ import 'package:get/get.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/jadwal_penyaluran_controller.dart'; import 'package:penyaluran_app/app/modules/petugas_desa/controllers/jadwal_penyaluran_controller.dart';
import 'package:penyaluran_app/app/theme/app_theme.dart'; import 'package:penyaluran_app/app/theme/app_theme.dart';
import 'package:penyaluran_app/app/data/models/skema_bantuan_model.dart';
import 'package:penyaluran_app/app/data/models/pengajuan_kelayakan_bantuan_model.dart';
class TambahPenyaluranView extends GetView<JadwalPenyaluranController> { class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
const TambahPenyaluranView({super.key}); const TambahPenyaluranView({super.key});
@ -23,21 +25,38 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
final formKey = GlobalKey<FormState>(); final formKey = GlobalKey<FormState>();
final TextEditingController namaController = TextEditingController(); final TextEditingController namaController = TextEditingController();
final TextEditingController deskripsiController = TextEditingController(); final TextEditingController deskripsiController = TextEditingController();
final TextEditingController jumlahPenerimaController =
TextEditingController();
final TextEditingController tanggalPenyaluranController = final TextEditingController tanggalPenyaluranController =
TextEditingController(); TextEditingController();
final TextEditingController waktuPenyaluranController = final TextEditingController waktuPenyaluranController =
TextEditingController(); TextEditingController();
// Variabel untuk menyimpan nilai yang dipilih // Variabel untuk menyimpan nilai yang dipilih
final Rx<String?> selectedKategoriBantuanId = Rx<String?>(null); final Rx<String?> selectedSkemaBantuanId = Rx<String?>(null);
final Rx<String?> selectedLokasiPenyaluranId = Rx<String?>(null); final Rx<String?> selectedLokasiPenyaluranId = Rx<String?>(null);
final Rx<SkemaBantuanModel?> selectedSkemaBantuan =
Rx<SkemaBantuanModel?>(null);
final RxInt jumlahPenerima = 0.obs;
// Tanggal dan waktu penyaluran // Tanggal dan waktu penyaluran
final Rx<DateTime?> selectedDate = Rx<DateTime?>(null); final Rx<DateTime?> selectedDate = Rx<DateTime?>(null);
final Rx<TimeOfDay?> selectedTime = Rx<TimeOfDay?>(null); final Rx<TimeOfDay?> selectedTime = Rx<TimeOfDay?>(null);
// Fungsi untuk memuat data pengajuan kelayakan bantuan
Future<void> loadPengajuanKelayakan(String skemaId) async {
try {
final pengajuanData = await controller.supabaseService.client
.from('xx02_pengajuan_kelayakan_bantuan')
.select('*')
.eq('skema_bantuan_id', skemaId)
.eq('status', 'TERVERIFIKASI');
print('pengajuan $pengajuanData');
jumlahPenerima.value = pengajuanData.length;
} catch (e) {
print('Error loading pengajuan kelayakan: $e');
}
}
return Padding( return Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Form( child: Form(
@ -82,9 +101,9 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// Kategori Bantuan // Skema Bantuan
Text( Text(
'Kategori Bantuan', 'Skema Bantuan',
style: Theme.of(context).textTheme.titleSmall, style: Theme.of(context).textTheme.titleSmall,
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
@ -98,20 +117,25 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
vertical: 8, vertical: 8,
), ),
), ),
hint: const Text('Pilih kategori bantuan'), hint: const Text('Pilih skema bantuan'),
value: selectedKategoriBantuanId.value, value: selectedSkemaBantuanId.value,
items: controller.kategoriBantuanCache.entries items: controller.skemaBantuanCache.entries
.map((entry) => DropdownMenuItem<String>( .map((entry) => DropdownMenuItem<String>(
value: entry.key, value: entry.key,
child: Text(entry.value.nama ?? 'Tidak ada nama'), child: Text(entry.value.nama ?? 'Tidak ada nama'),
)) ))
.toList(), .toList(),
onChanged: (value) { onChanged: (value) async {
selectedKategoriBantuanId.value = value; selectedSkemaBantuanId.value = value;
if (value != null) {
selectedSkemaBantuan.value =
controller.skemaBantuanCache[value];
await loadPengajuanKelayakan(value);
}
}, },
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Kategori bantuan harus dipilih'; return 'Skema bantuan harus dipilih';
} }
return null; return null;
}, },
@ -154,17 +178,18 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
)), )),
const SizedBox(height: 16), const SizedBox(height: 16),
// Jumlah Penerima // Jumlah Penerima (Otomatis)
Text( Text(
'Jumlah Penerima', 'Jumlah Penerima',
style: Theme.of(context).textTheme.titleSmall, style: Theme.of(context).textTheme.titleSmall,
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
TextFormField( Obx(() => TextFormField(
controller: jumlahPenerimaController, readOnly: true,
keyboardType: TextInputType.number, controller: TextEditingController(
text: jumlahPenerima.value.toString()),
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Masukkan jumlah penerima', hintText: 'Jumlah penerima akan diambil otomatis',
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
@ -173,19 +198,97 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
vertical: 8, vertical: 8,
), ),
), ),
validator: (value) { )),
if (value == null || value.isEmpty) { const SizedBox(height: 8),
return 'Jumlah penerima tidak boleh kosong'; Obx(() => jumlahPenerima.value > 0
} ? TextButton.icon(
if (int.tryParse(value) == null) { onPressed: () async {
return 'Jumlah penerima harus berupa angka'; final pengajuanData = await controller
} .supabaseService.client
if (int.parse(value) <= 0) { .from('xx02_pengajuan_kelayakan_bantuan')
return 'Jumlah penerima harus lebih dari 0'; .select('*, warga:warga_id(*)')
} .eq('skema_bantuan_id',
return null; 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,
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const Text(
'Daftar Penerima Bantuan',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
), ),
),
IconButton(
onPressed: () => Get.back(),
icon: const Icon(Icons.close),
),
],
),
const SizedBox(height: 16),
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
child: DataTable(
columnSpacing: 20,
horizontalMargin: 20,
columns: const [
DataColumn(label: Text('No')),
DataColumn(label: Text('Nama')),
DataColumn(label: Text('NIK')),
DataColumn(label: Text('Alamat')),
],
rows: pengajuanData
.asMap()
.entries
.map((entry) {
final warga =
entry.value['warga'];
return DataRow(
cells: [
DataCell(
Text('${entry.key + 1}')),
DataCell(Text(
warga['nama_lengkap'] ??
'-')),
DataCell(Text(
warga['nik'] ?? '-')),
DataCell(Text(
warga['alamat'] ?? '-')),
],
);
}).toList(),
),
),
),
),
],
),
),
),
);
}
},
icon: const Icon(Icons.people),
label: const Text('Lihat Daftar Penerima'),
)
: const SizedBox.shrink()),
const SizedBox(height: 16), const SizedBox(height: 16),
// Tanggal Penyaluran // Tanggal Penyaluran
@ -321,10 +424,9 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
controller.tambahPenyaluran( controller.tambahPenyaluran(
nama: namaController.text, nama: namaController.text,
deskripsi: deskripsiController.text, deskripsi: deskripsiController.text,
kategoriBantuanId: selectedKategoriBantuanId.value!, skemaId: selectedSkemaBantuanId.value!,
lokasiPenyaluranId: selectedLokasiPenyaluranId.value!, lokasiPenyaluranId: selectedLokasiPenyaluranId.value!,
jumlahPenerima: jumlahPenerima: jumlahPenerima.value,
int.parse(jumlahPenerimaController.text),
tanggalPenyaluran: tanggalWaktuPenyaluran, tanggalPenyaluran: tanggalWaktuPenyaluran,
); );
} }

View File

@ -242,7 +242,7 @@ class SupabaseService extends GetxService {
.select('*') .select('*')
.gte('tanggal_penyaluran', todayUtc) .gte('tanggal_penyaluran', todayUtc)
.lt('tanggal_penyaluran', tomorrowUtc) .lt('tanggal_penyaluran', tomorrowUtc)
.inFilter('status', ['DISETUJUI', 'BERLANGSUNG', 'DIJADWALKAN']); .inFilter('status', ['AKTIF', 'DIJADWALKAN']);
return response; return response;
} catch (e) { } catch (e) {
@ -267,7 +267,7 @@ class SupabaseService extends GetxService {
.select('*') .select('*')
.gte('tanggal_penyaluran', tomorrowUtc) .gte('tanggal_penyaluran', tomorrowUtc)
.lt('tanggal_penyaluran', weekUtc) .lt('tanggal_penyaluran', weekUtc)
.inFilter('status', ['DISETUJUI', 'DIJADWALKAN']); .inFilter('status', ['DIJADWALKAN']);
return response; return response;
} catch (e) { } catch (e) {
@ -276,12 +276,12 @@ class SupabaseService extends GetxService {
} }
} }
Future<List<Map<String, dynamic>>?> getJadwalSelesai() async { Future<List<Map<String, dynamic>>?> getJadwalTerlaksana() async {
try { try {
final response = await client final response = await client
.from('penyaluran_bantuan') .from('penyaluran_bantuan')
.select('*') .select('*')
.eq('status', 'SELESAI') .eq('status', 'TERLAKSANA')
.order('tanggal_penyaluran', ascending: false) .order('tanggal_penyaluran', ascending: false)
.limit(10); .limit(10);
@ -1124,12 +1124,33 @@ class SupabaseService extends GetxService {
} }
// Fungsi untuk menambahkan penyaluran baru // Fungsi untuk menambahkan penyaluran baru
Future<void> tambahPenyaluran(Map<String, dynamic> penyaluran) async { Future<Map<String, dynamic>> tambahPenyaluran(
Map<String, dynamic> penyaluran) async {
try { try {
await client.from('penyaluran_bantuan').insert(penyaluran); final response = await client
.from('penyaluran_bantuan')
.insert(penyaluran)
.select()
.single();
return response;
} catch (e) { } catch (e) {
print('Error menambahkan penyaluran: $e'); print('Error menambahkan penyaluran: $e');
throw e.toString(); throw e.toString();
} }
} }
Future<List<Map<String, dynamic>>?> getAllSkemaBantuan() async {
try {
final response = await client
.from('xx02_skema_bantuan')
.select('*')
.order('created_at', ascending: false);
return response;
} catch (e) {
print('Error getting all skema bantuan: $e');
return null;
}
}
} }