From c54c0a27d914fcda57a032a84ef21bb048121831 Mon Sep 17 00:00:00 2001 From: Khafidh Fuadi Date: Sun, 9 Mar 2025 10:00:36 +0700 Subject: [PATCH] Tambahkan fitur konfirmasi penyaluran bantuan untuk Petugas Desa - Tambahkan kontroler untuk mengelola proses konfirmasi penerima - Buat tampilan konfirmasi penyaluran dengan validasi input - Tambahkan fitur pemilihan tanggal, foto bukti, dan tanda tangan - Perbarui rute untuk mendukung halaman konfirmasi - Integrasikan intl package untuk format tanggal dalam bahasa Indonesia --- .../controllers/penerima_controller.dart | 160 +++++ .../views/detail_penerima_view.dart | 12 +- .../views/konfirmasi_penerima_view.dart | 652 ++++++++++++++++++ lib/app/routes/app_pages.dart | 8 +- lib/app/routes/app_routes.dart | 2 + pubspec.lock | 8 + pubspec.yaml | 3 + 7 files changed, 835 insertions(+), 10 deletions(-) create mode 100644 lib/app/modules/petugas_desa/views/konfirmasi_penerima_view.dart diff --git a/lib/app/modules/petugas_desa/controllers/penerima_controller.dart b/lib/app/modules/petugas_desa/controllers/penerima_controller.dart index c110878..d18d898 100644 --- a/lib/app/modules/petugas_desa/controllers/penerima_controller.dart +++ b/lib/app/modules/petugas_desa/controllers/penerima_controller.dart @@ -1,10 +1,21 @@ import 'package:get/get.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; class PenerimaController extends GetxController { final RxList> daftarPenerima = >[].obs; final RxBool isLoading = false.obs; + // Variabel untuk halaman konfirmasi penerima + final RxBool isKonfirmasiChecked = false.obs; + final RxBool isIdentitasChecked = false.obs; + final RxBool isDataValidChecked = false.obs; + final RxString tanggalPenyaluran = ''.obs; + final RxString fotoBuktiPath = ''.obs; + final RxString tandaTanganPath = ''.obs; + final TextEditingController catatanController = TextEditingController(); + @override void onInit() { super.onInit(); @@ -20,6 +31,12 @@ class PenerimaController extends GetxController { } } + @override + void onClose() { + catatanController.dispose(); + super.onClose(); + } + void fetchDaftarPenerima() { isLoading.value = true; @@ -149,4 +166,147 @@ class PenerimaController extends GetxController { return null; } } + + // Fungsi untuk memilih tanggal penyaluran + Future pilihTanggalPenyaluran(BuildContext context) async { + final DateTime? picked = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2020), + lastDate: DateTime.now(), + builder: (context, child) { + return Theme( + data: ThemeData.light().copyWith( + colorScheme: const ColorScheme.light( + primary: Color(0xFF2E5077), + onPrimary: Colors.white, + surface: Colors.white, + onSurface: Colors.black, + ), + ), + child: child!, + ); + }, + ); + + if (picked != null) { + tanggalPenyaluran.value = + DateFormat('dd MMMM yyyy', 'id_ID').format(picked); + } + } + + // Fungsi untuk memilih foto bukti + void pilihFotoBukti() { + // Simulasi pemilihan foto + // Dalam implementasi nyata, gunakan image_picker + fotoBuktiPath.value = 'assets/images/bukti_penyaluran.jpg'; + } + + // Fungsi untuk menghapus foto bukti + void hapusFotoBukti() { + fotoBuktiPath.value = ''; + } + + // Fungsi untuk membuka signature pad + void bukaSignaturePad(BuildContext context) { + // Simulasi tanda tangan + // Dalam implementasi nyata, gunakan signature_pad atau library serupa + tandaTanganPath.value = 'assets/images/tanda_tangan.png'; + } + + // Fungsi untuk menghapus tanda tangan + void hapusTandaTangan() { + tandaTanganPath.value = ''; + } + + // Fungsi untuk konfirmasi penyaluran + void konfirmasiPenyaluran(String id) { + // Validasi input + if (!isKonfirmasiChecked.value) { + Get.snackbar( + 'Perhatian', + 'Anda harus mengkonfirmasi penyaluran bantuan', + backgroundColor: Colors.orange, + colorText: Colors.white, + ); + return; + } + + if (!isIdentitasChecked.value) { + Get.snackbar( + 'Perhatian', + 'Anda harus memverifikasi identitas penerima', + backgroundColor: Colors.orange, + colorText: Colors.white, + ); + return; + } + + if (!isDataValidChecked.value) { + Get.snackbar( + 'Perhatian', + 'Anda harus menyatakan kebenaran data', + backgroundColor: Colors.orange, + colorText: Colors.white, + ); + return; + } + + if (fotoBuktiPath.value.isEmpty) { + Get.snackbar( + 'Perhatian', + 'Bukti foto penyaluran harus diunggah', + backgroundColor: Colors.orange, + colorText: Colors.white, + ); + return; + } + + if (tandaTanganPath.value.isEmpty) { + Get.snackbar( + 'Perhatian', + 'Tanda tangan penerima harus diisi', + backgroundColor: Colors.orange, + colorText: Colors.white, + ); + return; + } + + // Simulasi proses konfirmasi + isLoading.value = true; + + // Dalam implementasi nyata, kirim data ke API + Future.delayed(const Duration(seconds: 2), () { + // Update status penerima + final index = + daftarPenerima.indexWhere((penerima) => penerima['id'] == id); + if (index != -1) { + final updatedPenerima = + Map.from(daftarPenerima[index]); + updatedPenerima['status'] = 'Selesai'; + daftarPenerima[index] = updatedPenerima; + } + + isLoading.value = false; + + // Reset form + isKonfirmasiChecked.value = false; + isIdentitasChecked.value = false; + isDataValidChecked.value = false; + fotoBuktiPath.value = ''; + tandaTanganPath.value = ''; + catatanController.clear(); + + // Tampilkan pesan sukses + Get.snackbar( + 'Sukses', + 'Konfirmasi penyaluran bantuan berhasil disimpan', + backgroundColor: Colors.green, + colorText: Colors.white, + ); + + // Kembali ke halaman sebelumnya + Get.back(); + }); + } } diff --git a/lib/app/modules/petugas_desa/views/detail_penerima_view.dart b/lib/app/modules/petugas_desa/views/detail_penerima_view.dart index 7c3c56b..a417e0f 100644 --- a/lib/app/modules/petugas_desa/views/detail_penerima_view.dart +++ b/lib/app/modules/petugas_desa/views/detail_penerima_view.dart @@ -38,14 +38,6 @@ class DetailPenerimaView extends GetView { return Scaffold( appBar: AppBar( title: const Text('Detail Penerima'), - actions: [ - IconButton( - icon: const Icon(Icons.edit), - onPressed: () { - // Implementasi edit penerima - }, - ), - ], ), body: SingleChildScrollView( child: Column( @@ -413,7 +405,9 @@ class DetailPenerimaView extends GetView { Expanded( child: ElevatedButton.icon( onPressed: () { - // Implementasi konfirmasi penyaluran + // Navigasi ke halaman konfirmasi penerima + Get.toNamed('/daftar-penerima/konfirmasi', + arguments: penerima['id']); }, icon: const Icon(Icons.check_circle), label: const Text('Konfirmasi Penyaluran'), diff --git a/lib/app/modules/petugas_desa/views/konfirmasi_penerima_view.dart b/lib/app/modules/petugas_desa/views/konfirmasi_penerima_view.dart new file mode 100644 index 0000000..d614e24 --- /dev/null +++ b/lib/app/modules/petugas_desa/views/konfirmasi_penerima_view.dart @@ -0,0 +1,652 @@ +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 KonfirmasiPenerimaView extends GetView { + const KonfirmasiPenerimaView({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('Konfirmasi Penerima'), + ), + body: const Center( + child: CircularProgressIndicator(), + ), + ); + } + + final penerima = controller.getPenerimaById(id); + + if (penerima == null) { + return Scaffold( + appBar: AppBar( + title: const Text('Konfirmasi Penerima'), + ), + body: const Center( + child: Text('Data penerima tidak ditemukan'), + ), + ); + } + + return Scaffold( + appBar: AppBar( + title: const Text('Konfirmasi Penerima'), + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Get.back(), + ), + ), + body: SingleChildScrollView( + child: Column( + children: [ + // Header dengan foto dan nama + _buildHeader(penerima), + + // Detail informasi penerima + _buildDetailInfo(penerima), + + // Detail jadwal dan bantuan + _buildDetailJadwalBantuan(penerima), + + // Form konfirmasi + _buildKonfirmasiForm(context, 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: 40, + backgroundColor: Colors.white, + child: penerima['foto'] != null + ? ClipRRect( + borderRadius: BorderRadius.circular(40), + child: Image.asset( + penerima['foto'], + width: 80, + height: 80, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Icon( + Icons.person, + size: 40, + color: AppTheme.primaryColor, + ); + }, + ), + ) + : const Icon( + Icons.person, + size: 40, + color: AppTheme.primaryColor, + ), + ), + const SizedBox(height: 12), + // Nama penerima + Text( + penerima['nama'] ?? 'Nama tidak tersedia', + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + const SizedBox(height: 4), + // NIK + Text( + penerima['nik'] ?? 'NIK tidak tersedia', + style: const TextStyle( + fontSize: 14, + color: Colors.white, + ), + ), + const SizedBox(height: 8), + // Badge status + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), + decoration: BoxDecoration( + color: penerima['status'] == 'Terjadwal' + ? AppTheme.scheduledColor + : AppTheme.completedColor, + borderRadius: BorderRadius.circular(20), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + penerima['status'] == 'Terjadwal' + ? Icons.event_available + : Icons.check_circle, + color: Colors.white, + size: 16, + ), + const SizedBox(width: 4), + Text( + penerima['status'] ?? 'Status tidak tersedia', + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ], + ), + ); + } + + 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), + Card( + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + _buildDetailRow('NIK', penerima['nik'] ?? '-'), + _buildDetailRow('No KK', penerima['noKK'] ?? '-'), + _buildDetailRow( + 'No Handphone', penerima['noHandphone'] ?? '-'), + _buildDetailRow('Email', penerima['email'] ?? '-'), + _buildDetailRow( + 'Jenis Kelamin', penerima['jenisKelamin'] ?? '-'), + _buildDetailRow('Agama', penerima['agama'] ?? '-'), + _buildDetailRow('Tempat, Tanggal Lahir', + penerima['tempatTanggalLahir'] ?? '-'), + _buildDetailRow( + 'Alamat Lengkap', penerima['alamatLengkap'] ?? '-'), + _buildDetailRow('Pekerjaan', penerima['pekerjaan'] ?? '-'), + _buildDetailRow('Pendidikan Terakhir', + penerima['pendidikanTerakhir'] ?? '-'), + ], + ), + ), + ), + ], + ), + ); + } + + Widget _buildDetailJadwalBantuan(Map penerima) { + // Simulasi data jadwal dan bantuan + final jadwalBantuan = { + 'tanggal': '15 Agustus 2023', + 'waktu': '09:00 - 12:00 WIB', + 'lokasi': 'Balai Desa Gunung Putri, Jl. Raya Gunung Putri No. 10', + 'jenisBantuan': 'Bantuan Sosial Tunai (BST)', + 'nilaiNominal': 'Rp 600.000', + 'keterangan': 'Bantuan diberikan dalam bentuk tunai' + }; + + return Container( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Detail Jadwal & Bantuan', + 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: Column( + children: [ + _buildDetailRow( + 'Tanggal Penyaluran', jadwalBantuan['tanggal'] ?? '-'), + _buildDetailRow('Waktu', jadwalBantuan['waktu'] ?? '-'), + _buildDetailRow('Lokasi', jadwalBantuan['lokasi'] ?? '-'), + _buildDetailRow( + 'Jenis Bantuan', jadwalBantuan['jenisBantuan'] ?? '-'), + _buildDetailRow( + 'Nilai Nominal', jadwalBantuan['nilaiNominal'] ?? '-'), + _buildDetailRow( + 'Keterangan', jadwalBantuan['keterangan'] ?? '-'), + ], + ), + ), + ), + ], + ), + ); + } + + Widget _buildDetailRow(String label, String value) { + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 140, + child: Text( + label, + style: const TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + ), + Expanded( + child: Text( + value, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + ); + } + + Widget _buildKonfirmasiForm( + BuildContext context, Map penerima) { + return Container( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Konfirmasi Penyaluran Bantuan', + 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: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Status penyaluran + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: AppTheme.infoColor.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: AppTheme.infoColor.withOpacity(0.2), + shape: BoxShape.circle, + ), + child: const Icon( + Icons.info_outline, + color: AppTheme.infoColor, + ), + ), + const SizedBox(width: 12), + const Expanded( + child: Text( + 'Pastikan penerima hadir dan menerima bantuan sesuai dengan ketentuan.', + style: TextStyle( + fontSize: 14, + color: AppTheme.infoColor, + ), + ), + ), + ], + ), + ), + const SizedBox(height: 20), + + // Checkbox persetujuan petugas + const Text( + 'Persetujuan Petugas', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 12), + + // Checkbox 1 + Row( + children: [ + Obx(() => Checkbox( + value: controller.isKonfirmasiChecked.value, + onChanged: (value) { + controller.isKonfirmasiChecked.value = + value ?? false; + }, + activeColor: AppTheme.primaryColor, + )), + const Expanded( + child: Text( + 'Saya konfirmasi bahwa penerima ini telah hadir dan menerima bantuan sesuai dengan ketentuan', + style: TextStyle(fontSize: 14), + ), + ), + ], + ), + + // Checkbox 2 + Row( + children: [ + Obx(() => Checkbox( + value: controller.isIdentitasChecked.value, + onChanged: (value) { + controller.isIdentitasChecked.value = + value ?? false; + }, + activeColor: AppTheme.primaryColor, + )), + const Expanded( + child: Text( + 'Saya telah memverifikasi identitas penerima sesuai dengan KTP/KK yang ditunjukkan', + style: TextStyle(fontSize: 14), + ), + ), + ], + ), + + // Checkbox 3 + Row( + children: [ + Obx(() => Checkbox( + value: controller.isDataValidChecked.value, + onChanged: (value) { + controller.isDataValidChecked.value = + value ?? false; + }, + activeColor: AppTheme.primaryColor, + )), + const Expanded( + child: Text( + 'Saya menyatakan bahwa data yang diinput adalah benar dan dapat dipertanggungjawabkan', + style: TextStyle(fontSize: 14), + ), + ), + ], + ), + + const SizedBox(height: 20), + + // Form bukti foto + const Text( + 'Bukti Foto Penyaluran', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 8), + InkWell( + onTap: () => controller.pilihFotoBukti(), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 20), + decoration: BoxDecoration( + border: + Border.all(color: Colors.grey.shade300, width: 1), + borderRadius: BorderRadius.circular(10), + ), + child: Obx(() => controller.fotoBuktiPath.value.isEmpty + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.camera_alt, + color: AppTheme.primaryColor, + size: 40, + ), + const SizedBox(height: 8), + const Text( + 'Tambahkan Foto Bukti', + style: TextStyle( + color: AppTheme.primaryColor, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 4), + Text( + 'Format: JPG, PNG (Maks. 5MB)', + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade600, + ), + ), + ], + ) + : Stack( + alignment: Alignment.topRight, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.asset( + controller.fotoBuktiPath.value, + height: 200, + width: double.infinity, + fit: BoxFit.cover, + ), + ), + Positioned( + top: 8, + right: 8, + child: InkWell( + onTap: () => controller.hapusFotoBukti(), + child: Container( + padding: const EdgeInsets.all(4), + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: const Icon( + Icons.close, + color: Colors.red, + size: 20, + ), + ), + ), + ), + ], + )), + ), + ), + + const SizedBox(height: 20), + + // Tanda tangan digital penerima + const Text( + 'Tanda Tangan Digital Penerima', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 8), + InkWell( + onTap: () => controller.bukaSignaturePad(context), + child: Container( + height: 150, + width: double.infinity, + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(10), + ), + child: Obx(() => controller.tandaTanganPath.value.isEmpty + ? const Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.draw, + color: AppTheme.primaryColor, + size: 40, + ), + SizedBox(height: 8), + Text( + 'Tap untuk menambahkan tanda tangan', + style: TextStyle( + color: AppTheme.primaryColor, + fontWeight: FontWeight.w500, + ), + ), + ], + ) + : Stack( + alignment: Alignment.topRight, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.asset( + controller.tandaTanganPath.value, + height: 150, + width: double.infinity, + fit: BoxFit.contain, + ), + ), + Positioned( + top: 8, + right: 8, + child: InkWell( + onTap: () => controller.hapusTandaTangan(), + child: Container( + padding: const EdgeInsets.all(4), + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: const Icon( + Icons.close, + color: Colors.red, + size: 20, + ), + ), + ), + ), + ], + )), + ), + ), + + const SizedBox(height: 20), + + // Form catatan + const Text( + 'Catatan Penyaluran (Opsional)', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 8), + TextField( + controller: controller.catatanController, + maxLines: 3, + decoration: InputDecoration( + hintText: 'Masukkan catatan penyaluran jika ada', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + ), + ], + ), + ), + ), + ], + ), + ); + } + + Widget _buildBottomButtons(Map penerima) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + spreadRadius: 1, + blurRadius: 5, + offset: const Offset(0, -3), + ), + ], + ), + child: Row( + children: [ + Expanded( + child: OutlinedButton( + onPressed: () => Get.back(), + child: const Text('Kembali'), + ), + ), + const SizedBox(width: 16), + Expanded( + child: Obx(() => ElevatedButton( + onPressed: controller.isKonfirmasiChecked.value && + controller.isIdentitasChecked.value && + controller.isDataValidChecked.value && + controller.fotoBuktiPath.value.isNotEmpty && + controller.tandaTanganPath.value.isNotEmpty + ? () => controller.konfirmasiPenyaluran(penerima['id']) + : null, + style: ElevatedButton.styleFrom( + backgroundColor: AppTheme.primaryColor, + disabledBackgroundColor: Colors.grey.shade300, + ), + child: const Text('Konfirmasi'), + )), + ), + ], + ), + ); + } +} diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index 5317048..fb83a71 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -12,7 +12,8 @@ import 'package:penyaluran_app/app/modules/petugas_desa/bindings/petugas_desa_bi 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/views/konfirmasi_penerima_view.dart'; + import 'package:penyaluran_app/app/modules/petugas_desa/bindings/penerima_binding.dart'; part 'app_routes.dart'; @@ -68,5 +69,10 @@ class AppPages { page: () => const DetailPenerimaView(), binding: PenerimaBinding(), ), + GetPage( + name: _Paths.konfirmasiPenerima, + page: () => const KonfirmasiPenerimaView(), + binding: PenerimaBinding(), + ), ]; } diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart index e40077f..2b27255 100644 --- a/lib/app/routes/app_routes.dart +++ b/lib/app/routes/app_routes.dart @@ -13,6 +13,7 @@ abstract class Routes { static const permintaanPenjadwalan = _Paths.permintaanPenjadwalan; static const daftarPenerima = _Paths.daftarPenerima; static const detailPenerima = _Paths.detailPenerima; + static const konfirmasiPenerima = _Paths.konfirmasiPenerima; } abstract class _Paths { @@ -28,4 +29,5 @@ abstract class _Paths { static const permintaanPenjadwalan = '/permintaan-penjadwalan'; static const daftarPenerima = '/daftar-penerima'; static const detailPenerima = '/daftar-penerima/detail'; + static const konfirmasiPenerima = '/daftar-penerima/konfirmasi'; } diff --git a/pubspec.lock b/pubspec.lock index 1b7a6ea..70a812c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -224,6 +224,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + intl: + dependency: "direct main" + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" jwt_decode: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7661e83..69f2068 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -52,6 +52,9 @@ dependencies: google_fonts: ^6.2.1 flutter_svg: ^2.0.17 + # Untuk format tanggal dalam bahasa Indonesia + intl: ^0.19.0 + dev_dependencies: flutter_test: sdk: flutter