Tambahkan properti tanggalWaktuSelesai pada model PenyaluranBantuanModel dan perbarui tampilan serta controller untuk mendukung rentang waktu penyaluran. Modifikasi logika di JadwalPenyaluranController untuk memperbarui status jadwal berdasarkan waktu mulai dan selesai. Perbarui tampilan TambahPenyaluranView untuk memungkinkan pemilihan waktu mulai dan selesai secara terpisah.
This commit is contained in:
@ -4,7 +4,6 @@ import 'package:intl/intl.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/data/models/skema_bantuan_model.dart';
|
||||
import 'package:penyaluran_app/app/data/models/pengajuan_kelayakan_bantuan_model.dart';
|
||||
|
||||
class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
const TambahPenyaluranView({super.key});
|
||||
@ -27,7 +26,8 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
final TextEditingController deskripsiController = TextEditingController();
|
||||
final TextEditingController tanggalPenyaluranController =
|
||||
TextEditingController();
|
||||
final TextEditingController waktuPenyaluranController =
|
||||
final TextEditingController waktuMulaiController = TextEditingController();
|
||||
final TextEditingController waktuSelesaiController =
|
||||
TextEditingController();
|
||||
|
||||
// Variabel untuk menyimpan nilai yang dipilih
|
||||
@ -39,7 +39,8 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
|
||||
// Tanggal dan waktu penyaluran
|
||||
final Rx<DateTime?> selectedDate = Rx<DateTime?>(null);
|
||||
final Rx<TimeOfDay?> selectedTime = Rx<TimeOfDay?>(null);
|
||||
final Rx<TimeOfDay?> selectedWaktuMulai = Rx<TimeOfDay?>(null);
|
||||
final Rx<TimeOfDay?> selectedWaktuSelesai = Rx<TimeOfDay?>(null);
|
||||
|
||||
// Fungsi untuk memuat data pengajuan kelayakan bantuan
|
||||
Future<void> loadPengajuanKelayakan(String skemaId) async {
|
||||
@ -200,6 +201,15 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
),
|
||||
)),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Info: Jumlah penerima diambil dari data pengajuan kelayakan bantuan yang telah terverifikasi untuk skema bantuan yang dipilih.',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Obx(() => jumlahPenerima.value > 0
|
||||
? TextButton.icon(
|
||||
onPressed: () async {
|
||||
@ -312,10 +322,13 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
suffixIcon: const Icon(Icons.calendar_today),
|
||||
),
|
||||
onTap: () async {
|
||||
// Tanggal minimal adalah 1 hari setelah hari ini
|
||||
final DateTime tomorrow =
|
||||
DateTime.now().add(const Duration(days: 1));
|
||||
final DateTime? pickedDate = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: DateTime.now(),
|
||||
firstDate: DateTime.now(),
|
||||
initialDate: tomorrow,
|
||||
firstDate: tomorrow,
|
||||
lastDate: DateTime.now().add(const Duration(days: 365)),
|
||||
);
|
||||
if (pickedDate != null) {
|
||||
@ -331,45 +344,186 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// Hint info tanggal minimal
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue[50],
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: Colors.blue[200]!),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.info_outline,
|
||||
color: Colors.blue,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Tanggal pelaksanaan minimal 1 hari sebelum dijadwalkan',
|
||||
style: TextStyle(
|
||||
color: Colors.blue[900],
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Waktu Penyaluran
|
||||
// Rentang Waktu Penyaluran
|
||||
Text(
|
||||
'Waktu Penyaluran',
|
||||
'Rentang Waktu Penyaluran',
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: waktuPenyaluranController,
|
||||
readOnly: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Pilih waktu penyaluran',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
|
||||
// Waktu Mulai
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('Waktu Mulai'),
|
||||
const SizedBox(height: 4),
|
||||
TextFormField(
|
||||
controller: waktuMulaiController,
|
||||
readOnly: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Mulai',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 8,
|
||||
),
|
||||
suffixIcon: const Icon(Icons.access_time),
|
||||
),
|
||||
onTap: () async {
|
||||
final TimeOfDay? pickedTime = await showTimePicker(
|
||||
context: context,
|
||||
initialTime: TimeOfDay.now(),
|
||||
);
|
||||
if (pickedTime != null) {
|
||||
selectedWaktuMulai.value = pickedTime;
|
||||
waktuMulaiController.text =
|
||||
'${pickedTime.hour.toString().padLeft(2, '0')}:${pickedTime.minute.toString().padLeft(2, '0')}';
|
||||
|
||||
// Jika waktu selesai belum dipilih atau lebih awal dari waktu mulai
|
||||
if (selectedWaktuSelesai.value == null ||
|
||||
(selectedWaktuSelesai.value != null &&
|
||||
(pickedTime.hour >
|
||||
selectedWaktuSelesai
|
||||
.value!.hour ||
|
||||
(pickedTime.hour ==
|
||||
selectedWaktuSelesai
|
||||
.value!.hour &&
|
||||
pickedTime.minute >=
|
||||
selectedWaktuSelesai
|
||||
.value!.minute)))) {
|
||||
// Set waktu selesai 1 jam setelah waktu mulai
|
||||
final TimeOfDay defaultSelesai = TimeOfDay(
|
||||
hour: (pickedTime.hour + 1) % 24,
|
||||
minute: pickedTime.minute,
|
||||
);
|
||||
selectedWaktuSelesai.value = defaultSelesai;
|
||||
waktuSelesaiController.text =
|
||||
'${defaultSelesai.hour.toString().padLeft(2, '0')}:${defaultSelesai.minute.toString().padLeft(2, '0')}';
|
||||
}
|
||||
}
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Waktu mulai harus dipilih';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 8,
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('Waktu Selesai'),
|
||||
const SizedBox(height: 4),
|
||||
TextFormField(
|
||||
controller: waktuSelesaiController,
|
||||
readOnly: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Selesai',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 8,
|
||||
),
|
||||
suffixIcon: const Icon(Icons.access_time),
|
||||
),
|
||||
onTap: () async {
|
||||
// Pastikan waktu mulai sudah dipilih
|
||||
if (selectedWaktuMulai.value == null) {
|
||||
Get.snackbar(
|
||||
'Perhatian',
|
||||
'Silakan pilih waktu mulai terlebih dahulu',
|
||||
backgroundColor: Colors.amber,
|
||||
colorText: Colors.black,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final TimeOfDay? pickedTime = await showTimePicker(
|
||||
context: context,
|
||||
initialTime: selectedWaktuSelesai.value ??
|
||||
TimeOfDay(
|
||||
hour: (selectedWaktuMulai.value!.hour + 1) %
|
||||
24,
|
||||
minute: selectedWaktuMulai.value!.minute,
|
||||
),
|
||||
);
|
||||
if (pickedTime != null) {
|
||||
// Validasi waktu selesai harus setelah waktu mulai
|
||||
if (pickedTime.hour <
|
||||
selectedWaktuMulai.value!.hour ||
|
||||
(pickedTime.hour ==
|
||||
selectedWaktuMulai.value!.hour &&
|
||||
pickedTime.minute <=
|
||||
selectedWaktuMulai.value!.minute)) {
|
||||
Get.snackbar(
|
||||
'Perhatian',
|
||||
'Waktu selesai harus setelah waktu mulai',
|
||||
backgroundColor: Colors.amber,
|
||||
colorText: Colors.black,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
selectedWaktuSelesai.value = pickedTime;
|
||||
waktuSelesaiController.text =
|
||||
'${pickedTime.hour.toString().padLeft(2, '0')}:${pickedTime.minute.toString().padLeft(2, '0')}';
|
||||
}
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Waktu selesai harus dipilih';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
suffixIcon: const Icon(Icons.access_time),
|
||||
),
|
||||
onTap: () async {
|
||||
final TimeOfDay? pickedTime = await showTimePicker(
|
||||
context: context,
|
||||
initialTime: TimeOfDay.now(),
|
||||
);
|
||||
if (pickedTime != null) {
|
||||
selectedTime.value = pickedTime;
|
||||
waktuPenyaluranController.text =
|
||||
'${pickedTime.hour.toString().padLeft(2, '0')}:${pickedTime.minute.toString().padLeft(2, '0')}';
|
||||
}
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Waktu penyaluran harus dipilih';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
@ -407,16 +561,29 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
if (formKey.currentState!.validate()) {
|
||||
// Gabungkan tanggal dan waktu
|
||||
DateTime? tanggalWaktuPenyaluran;
|
||||
// Gabungkan tanggal dan waktu mulai
|
||||
DateTime? tanggalWaktuMulai;
|
||||
if (selectedDate.value != null &&
|
||||
selectedTime.value != null) {
|
||||
tanggalWaktuPenyaluran = DateTime(
|
||||
selectedWaktuMulai.value != null) {
|
||||
tanggalWaktuMulai = DateTime(
|
||||
selectedDate.value!.year,
|
||||
selectedDate.value!.month,
|
||||
selectedDate.value!.day,
|
||||
selectedTime.value!.hour,
|
||||
selectedTime.value!.minute,
|
||||
selectedWaktuMulai.value!.hour,
|
||||
selectedWaktuMulai.value!.minute,
|
||||
).toLocal();
|
||||
}
|
||||
|
||||
// Gabungkan tanggal dan waktu selesai
|
||||
DateTime? tanggalWaktuSelesai;
|
||||
if (selectedDate.value != null &&
|
||||
selectedWaktuSelesai.value != null) {
|
||||
tanggalWaktuSelesai = DateTime(
|
||||
selectedDate.value!.year,
|
||||
selectedDate.value!.month,
|
||||
selectedDate.value!.day,
|
||||
selectedWaktuSelesai.value!.hour,
|
||||
selectedWaktuSelesai.value!.minute,
|
||||
).toLocal();
|
||||
}
|
||||
|
||||
@ -427,7 +594,10 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
skemaId: selectedSkemaBantuanId.value!,
|
||||
lokasiPenyaluranId: selectedLokasiPenyaluranId.value!,
|
||||
jumlahPenerima: jumlahPenerima.value,
|
||||
tanggalPenyaluran: tanggalWaktuPenyaluran,
|
||||
tanggalPenyaluran: tanggalWaktuMulai,
|
||||
tanggalWaktuSelesai: tanggalWaktuSelesai,
|
||||
kategoriBantuanId:
|
||||
selectedSkemaBantuan.value!.kategoriBantuanId!,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
Reference in New Issue
Block a user