From e881b2e37fa3ce6e6e135ad73d18741e17dd6bbd Mon Sep 17 00:00:00 2001 From: Khafidh Fuadi Date: Tue, 25 Mar 2025 21:54:15 +0700 Subject: [PATCH] Perbarui logika pengambilan data penerima penyaluran di WargaDashboardController dengan menambahkan pengecekan ID pengguna dan logging untuk debugging. Modifikasi tampilan di WargaPenerimaanView dan WargaPengaduanView untuk meningkatkan pengalaman pengguna dengan menambahkan indikator refresh dan memperbaiki layout. Perbarui BantuanCard untuk menampilkan informasi dengan lebih baik dan menambahkan tombol aksi untuk detail. Implementasikan CustomScrollView untuk stabilitas tampilan yang lebih baik. --- .../arm64-v8a/configure_fingerprint.bin | 24 +- .../armeabi-v7a/configure_fingerprint.bin | 24 +- .../626b5o2n/x86/configure_fingerprint.bin | 24 +- .../626b5o2n/x86_64/configure_fingerprint.bin | 24 +- .../warga_dashboard_controller.dart | 191 +++--- .../warga/views/warga_penerimaan_view.dart | 76 ++- .../warga/views/warga_pengaduan_view.dart | 574 +++++++++++----- lib/app/widgets/bantuan_card.dart | 643 ++++++++++-------- 8 files changed, 994 insertions(+), 586 deletions(-) diff --git a/android/app/.cxx/Debug/626b5o2n/arm64-v8a/configure_fingerprint.bin b/android/app/.cxx/Debug/626b5o2n/arm64-v8a/configure_fingerprint.bin index e32522c..a8512e8 100644 --- a/android/app/.cxx/Debug/626b5o2n/arm64-v8a/configure_fingerprint.bin +++ b/android/app/.cxx/Debug/626b5o2n/arm64-v8a/configure_fingerprint.bin @@ -2,27 +2,27 @@ C/C++ Structured LogO M KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC A -?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  2 2 +?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  ɚ2 2  -}D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\additional_project_files.txt  2  2~ +}D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\additional_project_files.txt  ɚ2  2~ | -zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\android_gradle_build.json  2 2 +zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\android_gradle_build.json  ɚ2 2  -D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\android_gradle_build_mini.json  2 2p +D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\android_gradle_build_mini.json  ɚ2 2p n -lD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build.ninja  2 2t +lD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build.ninja  ɚ2 2t r -pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build.ninja.txt  2y +pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build.ninja.txt  ɚ2y w -uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build_file_index.txt  2 K 2z +uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build_file_index.txt  ɚ2 K 2z x -vD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\compile_commands.json  2 ~ +vD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\compile_commands.json  ɚ2 ~ | -zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\compile_commands.json.bin  2 +zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\compile_commands.json.bin  ɚ2   -D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\metadata_generation_command.txt  2  2w +D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\metadata_generation_command.txt  ɚ2  2w u -sD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\prefab_config.json  2  ( 2| +sD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\prefab_config.json  ɚ2  ( 2| z -xD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\symbol_folder_index.txt  2  o 2 \ No newline at end of file +xD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\symbol_folder_index.txt  ɚ2  o 2 \ No newline at end of file diff --git a/android/app/.cxx/Debug/626b5o2n/armeabi-v7a/configure_fingerprint.bin b/android/app/.cxx/Debug/626b5o2n/armeabi-v7a/configure_fingerprint.bin index e6b3034..62bb516 100644 --- a/android/app/.cxx/Debug/626b5o2n/armeabi-v7a/configure_fingerprint.bin +++ b/android/app/.cxx/Debug/626b5o2n/armeabi-v7a/configure_fingerprint.bin @@ -2,27 +2,27 @@ C/C++ Structured LogO M KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC A -?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  2 2 +?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  Ԛ2 2  -D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\additional_project_files.txt  2  2 +D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\additional_project_files.txt  Ԛ2  2 ~ -|D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\android_gradle_build.json  2 2 +|D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\android_gradle_build.json  Ԛ2 2  -D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\android_gradle_build_mini.json  2 2r +D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\android_gradle_build_mini.json  Ԛ2 2r p -nD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja  2 2v +nD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja  Ԛ2 2v t -rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja.txt  2{ +rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja.txt  Ԛ2{ y -wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build_file_index.txt  2 K 2| +wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build_file_index.txt  Ԛ2 K 2| z -xD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\compile_commands.json  2  +xD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\compile_commands.json  Ԛ2  ~ -|D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\compile_commands.json.bin  2 +|D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\compile_commands.json.bin  Ԛ2   -D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\metadata_generation_command.txt  2  2y +D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\metadata_generation_command.txt  Ԛ2  2y w -uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\prefab_config.json  2  ( 2~ +uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\prefab_config.json  Ԛ2  ( 2~ | -zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\symbol_folder_index.txt  2  q 2 \ No newline at end of file +zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\symbol_folder_index.txt  Ԛ2  q 2 \ No newline at end of file diff --git a/android/app/.cxx/Debug/626b5o2n/x86/configure_fingerprint.bin b/android/app/.cxx/Debug/626b5o2n/x86/configure_fingerprint.bin index 007ec45..35bb6c6 100644 --- a/android/app/.cxx/Debug/626b5o2n/x86/configure_fingerprint.bin +++ b/android/app/.cxx/Debug/626b5o2n/x86/configure_fingerprint.bin @@ -2,27 +2,27 @@ C/C++ Structured LogO M KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC A -?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  ؔ2 2{ +?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  ښ2 2{ y -wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\additional_project_files.txt  ؔ2  2x +wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\additional_project_files.txt  ښ2  2x v -tD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\android_gradle_build.json  ؔ2 2} +tD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\android_gradle_build.json  ښ2 2} { -yD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\android_gradle_build_mini.json  ؔ2 2j +yD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\android_gradle_build_mini.json  ښ2 2j h -fD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build.ninja  ؔ2 2n +fD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build.ninja  ښ2 2n l -jD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build.ninja.txt  ؔ2s +jD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build.ninja.txt  ښ2s q -oD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build_file_index.txt  ؔ2 K 2t +oD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build_file_index.txt  ښ2 K 2t r -pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\compile_commands.json  ؔ2 x +pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\compile_commands.json  ښ2 x v -tD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\compile_commands.json.bin  ؔ2 +tD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\compile_commands.json.bin  ښ2 ~ | -zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\metadata_generation_command.txt  ؔ2  2q +zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\metadata_generation_command.txt  ښ2  2q o -mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\prefab_config.json  ؔ2  ( 2v +mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\prefab_config.json  ښ2  ( 2v t -rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\symbol_folder_index.txt  ؔ2  i 2 \ No newline at end of file +rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\symbol_folder_index.txt  ښ2  i 2 \ No newline at end of file diff --git a/android/app/.cxx/Debug/626b5o2n/x86_64/configure_fingerprint.bin b/android/app/.cxx/Debug/626b5o2n/x86_64/configure_fingerprint.bin index 1f5e3b8..379d475 100644 --- a/android/app/.cxx/Debug/626b5o2n/x86_64/configure_fingerprint.bin +++ b/android/app/.cxx/Debug/626b5o2n/x86_64/configure_fingerprint.bin @@ -2,27 +2,27 @@ C/C++ Structured LogO M KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC A -?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  2 2~ +?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  ߚ2 2~ | -zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\additional_project_files.txt  2  2{ +zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\additional_project_files.txt  ߚ2  2{ y -wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\android_gradle_build.json  2 2 +wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\android_gradle_build.json  ߚ2 2 ~ -|D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\android_gradle_build_mini.json  2 2m +|D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\android_gradle_build_mini.json  ߚ2 2m k -iD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja  2 2q +iD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja  ߚ2 2q o -mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja.txt  2v +mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja.txt  ߚ2v t -rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build_file_index.txt  2 K 2w +rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build_file_index.txt  ߚ2 K 2w u -sD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\compile_commands.json  2 { +sD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\compile_commands.json  ߚ2 { y -wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\compile_commands.json.bin  2 +wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\compile_commands.json.bin  ߚ2   -}D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\metadata_generation_command.txt  2  2t +}D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\metadata_generation_command.txt  ߚ2  2t r -pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\prefab_config.json  2  ( 2y +pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\prefab_config.json  2  ( 2y w -uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\symbol_folder_index.txt  2  l 2 \ No newline at end of file +uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\symbol_folder_index.txt  2  l 2 \ No newline at end of file diff --git a/lib/app/modules/warga/controllers/warga_dashboard_controller.dart b/lib/app/modules/warga/controllers/warga_dashboard_controller.dart index 218e328..a0049c8 100644 --- a/lib/app/modules/warga/controllers/warga_dashboard_controller.dart +++ b/lib/app/modules/warga/controllers/warga_dashboard_controller.dart @@ -211,8 +211,18 @@ class WargaDashboardController extends GetxController { // Reset data terlebih dahulu untuk memastikan tidak ada data lama yang tersimpan penerimaPenyaluran.clear(); + // Log untuk debugging + print('DEBUG PENERIMAAN: Memulai fetchPenerimaPenyaluran()'); + + // Pastikan user sudah login dan memiliki ID + if (user?.id == null) { + print('DEBUG PENERIMAAN: User ID null, tidak bisa mengambil data'); + return []; + } + // Gunakan langsung ID pengguna sebagai warga_id final wargaId = user!.id; + print('DEBUG PENERIMAAN: Mengambil data untuk warga ID: $wargaId'); // Ambil data penerima penyaluran dengan join ke warga, stok bantuan, dan penyaluran bantuan final response = @@ -230,105 +240,126 @@ class WargaDashboardController extends GetxController { ) ''').eq('warga_id', wargaId).order('created_at', ascending: false); + print( + 'DEBUG PENERIMAAN: Respons diterima dengan ${response.length} item'); + final List penerima = []; // Loop melalui setiap data penerima for (var item in response) { - // Pastikan data penerima sesuai dengan tipe data yang diharapkan - Map sanitizedPenerimaData = - Map.from(item); + try { + // Pastikan data penerima sesuai dengan tipe data yang diharapkan + Map sanitizedPenerimaData = + Map.from(item); - // Konversi jumlah_bantuan ke double jika bertipe String - if (sanitizedPenerimaData['jumlah_bantuan'] is String) { - sanitizedPenerimaData['jumlah_bantuan'] = - double.tryParse(sanitizedPenerimaData['jumlah_bantuan']) ?? 0.0; - } - - // Ambil data dari stok bantuan jika tersedia - if (sanitizedPenerimaData['stok_bantuan'] != null) { - // Cek apakah bantuan berupa uang atau barang - final isUang = - sanitizedPenerimaData['stok_bantuan']['is_uang'] ?? false; - sanitizedPenerimaData['is_uang'] = isUang; - - // Ambil satuan bantuan - final satuan = sanitizedPenerimaData['stok_bantuan']['satuan'] ?? ''; - sanitizedPenerimaData['satuan'] = satuan; - - // Ambil nama kategori bantuan - if (sanitizedPenerimaData['stok_bantuan']['kategori_bantuan'] != - null) { - final kategoriNama = sanitizedPenerimaData['stok_bantuan'] - ['kategori_bantuan']['nama'] ?? - ''; - sanitizedPenerimaData['kategori_nama'] = kategoriNama; - } - } - - // Ambil data dari penyaluran bantuan jika tersedia - if (sanitizedPenerimaData['penyaluran_bantuan'] != null) { - // Ambil nama penyaluran - final namaPenyaluran = - sanitizedPenerimaData['penyaluran_bantuan']['nama'] ?? ''; - sanitizedPenerimaData['nama_penyaluran'] = namaPenyaluran; - - // Ambil deskripsi penyaluran - final deskripsiPenyaluran = - sanitizedPenerimaData['penyaluran_bantuan']['deskripsi'] ?? ''; - sanitizedPenerimaData['deskripsi_penyaluran'] = deskripsiPenyaluran; - - // Ambil status penyaluran - final statusPenyaluran = - sanitizedPenerimaData['penyaluran_bantuan']['status'] ?? ''; - sanitizedPenerimaData['status_penyaluran'] = statusPenyaluran; - - // Ambil lokasi penyaluran jika tersedia - if (sanitizedPenerimaData['penyaluran_bantuan'] - ['lokasi_penyaluran'] != - null) { - final lokasiNama = sanitizedPenerimaData['penyaluran_bantuan'] - ['lokasi_penyaluran']['nama'] ?? - ''; - sanitizedPenerimaData['lokasi_penyaluran_nama'] = lokasiNama; - - final lokasiAlamat = sanitizedPenerimaData['penyaluran_bantuan'] - ['lokasi_penyaluran']['alamat_lengkap'] ?? - ''; - sanitizedPenerimaData['lokasi_penyaluran_alamat'] = lokasiAlamat; + // Konversi jumlah_bantuan ke double jika bertipe String + if (sanitizedPenerimaData['jumlah_bantuan'] is String) { + sanitizedPenerimaData['jumlah_bantuan'] = + double.tryParse(sanitizedPenerimaData['jumlah_bantuan']) ?? 0.0; } - // Ambil kategori bantuan dari relasi langsung jika ada - if (sanitizedPenerimaData['penyaluran_bantuan']['kategori_bantuan'] != - null) { - final kategoriNama = sanitizedPenerimaData['penyaluran_bantuan'] - ['kategori_bantuan']['nama'] ?? - ''; - // Jika belum ada kategori_nama dari stok_bantuan, gunakan dari relasi langsung - if (sanitizedPenerimaData['kategori_nama'] == null || - sanitizedPenerimaData['kategori_nama'].isEmpty) { + // Ambil data dari stok bantuan jika tersedia + if (sanitizedPenerimaData['stok_bantuan'] != null) { + // Cek apakah bantuan berupa uang atau barang + final isUang = + sanitizedPenerimaData['stok_bantuan']['is_uang'] ?? false; + sanitizedPenerimaData['is_uang'] = isUang; + + // Ambil satuan bantuan + final satuan = + sanitizedPenerimaData['stok_bantuan']['satuan'] ?? ''; + sanitizedPenerimaData['satuan'] = satuan; + + // Ambil nama kategori bantuan + if (sanitizedPenerimaData['stok_bantuan']['kategori_bantuan'] != + null) { + final kategoriNama = sanitizedPenerimaData['stok_bantuan'] + ['kategori_bantuan']['nama'] ?? + ''; sanitizedPenerimaData['kategori_nama'] = kategoriNama; } } - } - var model = PenerimaPenyaluranModel.fromJson(sanitizedPenerimaData); - penerima.add(model); + // Ambil data dari penyaluran bantuan jika tersedia + if (sanitizedPenerimaData['penyaluran_bantuan'] != null) { + // Ambil nama penyaluran + final namaPenyaluran = + sanitizedPenerimaData['penyaluran_bantuan']['nama'] ?? ''; + sanitizedPenerimaData['nama_penyaluran'] = namaPenyaluran; + + // Ambil deskripsi penyaluran + final deskripsiPenyaluran = + sanitizedPenerimaData['penyaluran_bantuan']['deskripsi'] ?? ''; + sanitizedPenerimaData['deskripsi_penyaluran'] = deskripsiPenyaluran; + + // Ambil status penyaluran + final statusPenyaluran = + sanitizedPenerimaData['penyaluran_bantuan']['status'] ?? ''; + sanitizedPenerimaData['status_penyaluran'] = statusPenyaluran; + + // Ambil lokasi penyaluran jika tersedia + if (sanitizedPenerimaData['penyaluran_bantuan'] + ['lokasi_penyaluran'] != + null) { + final lokasiNama = sanitizedPenerimaData['penyaluran_bantuan'] + ['lokasi_penyaluran']['nama'] ?? + ''; + sanitizedPenerimaData['lokasi_penyaluran_nama'] = lokasiNama; + + final lokasiAlamat = sanitizedPenerimaData['penyaluran_bantuan'] + ['lokasi_penyaluran']['alamat_lengkap'] ?? + ''; + sanitizedPenerimaData['lokasi_penyaluran_alamat'] = lokasiAlamat; + } + + // Ambil kategori bantuan dari relasi langsung jika ada + if (sanitizedPenerimaData['penyaluran_bantuan'] + ['kategori_bantuan'] != + null) { + final kategoriNama = sanitizedPenerimaData['penyaluran_bantuan'] + ['kategori_bantuan']['nama'] ?? + ''; + // Jika belum ada kategori_nama dari stok_bantuan, gunakan dari relasi langsung + if (sanitizedPenerimaData['kategori_nama'] == null || + sanitizedPenerimaData['kategori_nama'].isEmpty) { + sanitizedPenerimaData['kategori_nama'] = kategoriNama; + } + } + } + + var model = PenerimaPenyaluranModel.fromJson(sanitizedPenerimaData); + penerima.add(model); + print('DEBUG PENERIMAAN: Berhasil parse item: ${model.id}'); + } catch (parseError) { + print('DEBUG PENERIMAAN: Error parsing item: $parseError'); + print('DEBUG PENERIMAAN: Data yang gagal di-parse: $item'); + } } - // Update nilai observable - penerimaPenyaluran.assignAll(penerima); + // Pastikan list tidak kosong sebelum assign + if (penerima.isNotEmpty) { + // Update nilai observable + penerimaPenyaluran.assignAll(penerima); + print( + 'DEBUG PENERIMAAN: Berhasil assign ${penerima.length} item ke list'); - var diterima = - penerima.where((p) => p.statusPenerimaan == 'DITERIMA').length; - totalPenyaluranDiterima.value = diterima; + var diterima = + penerima.where((p) => p.statusPenerimaan == 'DITERIMA').length; + totalPenyaluranDiterima.value = diterima; - // Log untuk debugging - print( - 'Berhasil memuat ${penerima.length} data penerimaan untuk warga ID: $wargaId'); + // Log untuk debugging + print( + 'Berhasil memuat ${penerima.length} data penerimaan untuk warga ID: $wargaId'); + } else { + print( + 'DEBUG PENERIMAAN: Tidak ada data penerimaan yang berhasil di-parse'); + } return penerima; } catch (e) { print('Error fetchPenerimaPenyaluran: $e'); + // Pastikan list kosong jika terjadi error + penerimaPenyaluran.clear(); return []; } } diff --git a/lib/app/modules/warga/views/warga_penerimaan_view.dart b/lib/app/modules/warga/views/warga_penerimaan_view.dart index aa17f63..6eb740f 100644 --- a/lib/app/modules/warga/views/warga_penerimaan_view.dart +++ b/lib/app/modules/warga/views/warga_penerimaan_view.dart @@ -15,13 +15,28 @@ class WargaPenerimaanView extends GetView { return const Center(child: CircularProgressIndicator()); } + // Debug print untuk melihat jumlah item + print( + 'DEBUG: Jumlah penerimaan tersedia: ${controller.penerimaPenyaluran.length}'); + return RefreshIndicator( onRefresh: () async { - controller.fetchData(); + // Tambahkan delay untuk memastikan refresh indicator terlihat + await Future.delayed(const Duration(milliseconds: 300)); + controller.fetchPenerimaPenyaluran(); }, child: controller.penerimaPenyaluran.isEmpty - ? _buildEmptyState() - : _buildPenerimaanList(), + ? ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: [ + SizedBox( + height: Get.height * + 0.7, // Pastikan tinggi cukup untuk memungkinkan scroll + child: _buildEmptyState(), + ), + ], + ) + : _buildPenerimaanList(context), ); }), ); @@ -86,21 +101,48 @@ class WargaPenerimaanView extends GetView { ); } - Widget _buildPenerimaanList() { - return ListView.builder( - padding: const EdgeInsets.all(16), - itemCount: controller.penerimaPenyaluran.length, - itemBuilder: (context, index) { - final item = controller.penerimaPenyaluran[index]; + Widget _buildPenerimaanList(BuildContext context) { + // Debug print untuk melihat jumlah item + print( + 'DEBUG: Membangun ListView dengan ${controller.penerimaPenyaluran.length} item bantuan'); - return BantuanCard( - item: item, - onTap: () { - // Navigasi ke detail penerimaan - Get.toNamed('/warga/detail-penerimaan', arguments: {'id': item.id}); - }, - ); - }, + // Menggunakan CustomScrollView dan SliverList untuk layout yang lebih stabil + return CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + SliverPadding( + padding: const EdgeInsets.all(16), + sliver: SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + // Pastikan index dalam batas array + if (index >= controller.penerimaPenyaluran.length) { + return const SizedBox.shrink(); + } + + final item = controller.penerimaPenyaluran[index]; + + // Debug + print('DEBUG: Membangun item $index dengan id: ${item.id}'); + + // Menggunakan SizedBox untuk memberikan batas lebar dan tinggi + return SizedBox( + width: MediaQuery.of(context).size.width, + child: BantuanCard( + item: item, + onTap: () { + // Navigasi ke detail penerimaan + Get.toNamed('/warga/detail-penerimaan', + arguments: {'id': item.id}); + }, + ), + ); + }, + childCount: controller.penerimaPenyaluran.length, + ), + ), + ), + ], ); } } diff --git a/lib/app/modules/warga/views/warga_pengaduan_view.dart b/lib/app/modules/warga/views/warga_pengaduan_view.dart index f96ea4b..8ea114c 100644 --- a/lib/app/modules/warga/views/warga_pengaduan_view.dart +++ b/lib/app/modules/warga/views/warga_pengaduan_view.dart @@ -13,13 +13,26 @@ class WargaPengaduanView extends GetView { return const Center(child: CircularProgressIndicator()); } + // Debug print untuk melihat jumlah item + print('DEBUG: Jumlah pengaduan tersedia: ${controller.pengaduan.length}'); + return RefreshIndicator( onRefresh: () async { + // Tambahkan delay untuk memastikan refresh indicator terlihat + await Future.delayed(const Duration(milliseconds: 300)); controller.fetchData(); }, child: controller.pengaduan.isEmpty - ? _buildEmptyState() - : _buildPengaduanList(), + ? ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: [ + SizedBox( + height: Get.height * 0.7, + child: _buildEmptyState(), + ), + ], + ) + : _buildPengaduanList(context), ); }); } @@ -56,195 +69,414 @@ class WargaPengaduanView extends GetView { ); } - Widget _buildPengaduanList() { - return ListView.builder( - padding: const EdgeInsets.all(16), - itemCount: controller.pengaduan.length, - itemBuilder: (context, index) { - final item = controller.pengaduan[index]; + Widget _buildPengaduanList(BuildContext context) { + // Log untuk debugging jumlah item + print( + 'DEBUG: Membangun ListView dengan ${controller.pengaduan.length} pengaduan'); - // Tentukan status dan warna berdasarkan status pengaduan - Color statusColor; - String statusText; + // Menggunakan CustomScrollView untuk layout yang lebih stabil + return CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + SliverPadding( + padding: const EdgeInsets.all(16), + sliver: SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + // Pastikan index valid + if (index >= controller.pengaduan.length) { + return const SizedBox.shrink(); + } - switch (item.status?.toUpperCase()) { - case 'MENUNGGU': - statusColor = Colors.orange; - statusText = 'Menunggu'; - break; - case 'TINDAKAN': - statusColor = Colors.blue; - statusText = 'Tindakan'; - break; - case 'SELESAI': - statusColor = Colors.green; - statusText = 'Selesai'; - break; - case 'DITOLAK': - statusColor = Colors.red; - statusText = 'Ditolak'; - break; - default: - statusColor = Colors.grey; - statusText = item.status ?? 'Tidak Diketahui'; - } + final item = controller.pengaduan[index]; + print( + 'DEBUG: Membangun item pengaduan $index dengan id: ${item.id}'); - return Card( - margin: const EdgeInsets.only(bottom: 16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 2, - child: InkWell( - onTap: () { - // Navigasi ke detail pengaduan - Get.toNamed('/warga/detail-pengaduan', - arguments: {'id': item.id}); - }, - borderRadius: BorderRadius.circular(12), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - item.judul ?? 'Pengaduan #${index + 1}', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 6, - ), - decoration: BoxDecoration( - color: statusColor.withOpacity(0.1), - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: statusColor, - ), - ), - child: Text( - statusText, - style: TextStyle( - color: statusColor, - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - ), - ], - ), - const SizedBox(height: 12), - - // Informasi penyaluran bantuan - if (item.penerimaPenyaluran != null) - Container( - padding: const EdgeInsets.all(8), - margin: const EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: Colors.blue.shade50, - borderRadius: BorderRadius.circular(8), + // Tentukan status dan warna berdasarkan status pengaduan + Color statusColor; + String statusText; + + switch (item.status?.toUpperCase()) { + case 'MENUNGGU': + statusColor = Colors.orange; + statusText = 'Menunggu'; + break; + case 'TINDAKAN': + statusColor = Colors.blue; + statusText = 'Tindakan'; + break; + case 'SELESAI': + statusColor = Colors.green; + statusText = 'Selesai'; + break; + case 'DITOLAK': + statusColor = Colors.red; + statusText = 'Ditolak'; + break; + default: + statusColor = Colors.grey; + statusText = item.status ?? 'Tidak Diketahui'; + } + + // Menggunakan SizedBox untuk memberikan batas lebar yang jelas + return SizedBox( + width: MediaQuery.of(context).size.width, + child: Card( + margin: const EdgeInsets.only(bottom: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: BorderSide( + color: statusColor.withOpacity(0.3), + width: 1, ), + ), + elevation: 3, + child: InkWell( + onTap: () { + // Navigasi ke detail pengaduan + Get.toNamed('/warga/detail-pengaduan', + arguments: {'id': item.id}); + }, + borderRadius: BorderRadius.circular(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ - Text( - 'Penyaluran: ${item.namaPenyaluran}', - style: const TextStyle( - fontWeight: FontWeight.bold, + // Header dengan warna sesuai status + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric( + horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: statusColor.withOpacity(0.1), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(12), + topRight: Radius.circular(12), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Row( + children: [ + Icon( + Icons.report_problem, + color: statusColor, + ), + const SizedBox(width: 8), + Flexible( + child: Text( + item.judul ?? + 'Pengaduan #${index + 1}', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: statusColor, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: statusColor, + width: 1.0, + ), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 3, + offset: const Offset(0, 1), + ), + ], + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + _getStatusIcon(item.status), + size: 14, + color: statusColor, + ), + const SizedBox(width: 4), + Text( + statusText, + style: TextStyle( + color: statusColor, + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ], + ), + ), + ], ), ), - const SizedBox(height: 4), - Row( - children: [ - Expanded( - child: Text( - 'Jenis: ${item.jenisBantuan}', - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade700, + + Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Informasi penyaluran bantuan jika ada + if (item.penerimaPenyaluran != null) + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + margin: const EdgeInsets.only(bottom: 16), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: Colors.blue.shade200, + width: 1.0, + ), + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.volunteer_activism, + color: Colors.blue.shade700, + size: 18, + ), + const SizedBox(width: 8), + Text( + 'Bantuan Terkait', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.blue.shade800, + ), + ), + ], + ), + const SizedBox(height: 8), + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: + BorderRadius.circular(8), + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + 'Penyaluran: ${item.namaPenyaluran ?? "Tidak tersedia"}', + style: const TextStyle( + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 6), + Row( + children: [ + Expanded( + child: _buildInfoItem( + 'Jenis', + item.jenisBantuan ?? + "Tidak tersedia", + ), + ), + Expanded( + child: _buildInfoItem( + 'Jumlah', + item.jumlahBantuan ?? + "Tidak tersedia", + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + + // Deskripsi pengaduan + if (item.deskripsi != null && + item.deskripsi!.isNotEmpty) + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + margin: const EdgeInsets.only(bottom: 16), + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: Colors.grey.shade200, + width: 1.0, + ), + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + 'Deskripsi Masalah:', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.grey.shade800, + ), + ), + const SizedBox(height: 6), + Text( + item.deskripsi!, + style: TextStyle( + color: Colors.grey.shade700, + ), + ), + ], + ), + ), + + // Informasi tanggal + Container( + width: double.infinity, + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Colors.grey.shade200, + ), + ), + child: Row( + children: [ + Icon( + Icons.calendar_today, + size: 16, + color: Colors.grey.shade600, + ), + const SizedBox(width: 8), + Text( + 'Dilaporkan pada: ', + style: TextStyle( + fontWeight: FontWeight.w500, + color: Colors.grey.shade700, + ), + ), + Expanded( + child: Text( + item.tanggalPengaduan != null + ? DateTimeHelper.formatDateTime( + item.tanggalPengaduan!) + : '-', + style: TextStyle( + color: Colors.grey.shade800, + ), + ), + ), + ], ), ), - ), - Expanded( - child: Text( - 'Jumlah: ${item.jumlahBantuan}', - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade700, - ), + ], + ), + ), + + // Footer dengan tombol aksi + Container( + width: double.infinity, + decoration: const BoxDecoration( + border: Border( + top: BorderSide( + color: Colors.black12, + width: 1, ), ), - ], + ), + padding: const EdgeInsets.symmetric( + horizontal: 16, vertical: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ElevatedButton.icon( + onPressed: () { + // Navigasi ke detail pengaduan + Get.toNamed('/warga/detail-pengaduan', + arguments: {'id': item.id}); + }, + icon: const Icon(Icons.visibility), + label: const Text('Lihat Detail'), + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: statusColor, + padding: const EdgeInsets.symmetric( + horizontal: 16, vertical: 8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ], + ), ), ], ), ), - - if (item.deskripsi != null && item.deskripsi!.isNotEmpty) - Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Text( - item.deskripsi!, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: Colors.grey.shade700, - ), - ), - ), - Row( - children: [ - Icon( - Icons.calendar_today, - size: 16, - color: Colors.grey.shade600, - ), - const SizedBox(width: 8), - Text( - item.tanggalPengaduan != null - ? DateTimeHelper.formatDateTime( - item.tanggalPengaduan!) - : '-', - style: TextStyle( - color: Colors.grey.shade600, - ), - ), - ], ), - const SizedBox(height: 16), - const Divider(height: 1), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - TextButton.icon( - onPressed: () { - // Navigasi ke detail pengaduan - Get.toNamed('/warga/detail-pengaduan', - arguments: {'id': item.id}); - }, - icon: const Icon(Icons.visibility), - label: const Text('Lihat Detail'), - ), - ], - ), - ], - ), + ); + }, + childCount: controller.pengaduan.length, ), ), - ); - }, + ), + ], + ); + } + + // Helper method untuk mendapatkan icon berdasarkan status + IconData _getStatusIcon(String? status) { + switch (status?.toUpperCase()) { + case 'MENUNGGU': + return Icons.hourglass_empty; + case 'TINDAKAN': + return Icons.engineering; + case 'SELESAI': + return Icons.check_circle; + case 'DITOLAK': + return Icons.cancel; + default: + return Icons.help_outline; + } + } + + // Widget untuk item informasi + Widget _buildInfoItem(String label, String value) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade600, + ), + ), + const SizedBox(height: 2), + Text( + value, + style: TextStyle( + fontWeight: FontWeight.w500, + color: Colors.grey.shade800, + ), + ), + ], ); } } diff --git a/lib/app/widgets/bantuan_card.dart b/lib/app/widgets/bantuan_card.dart index f11c779..5f20ee1 100644 --- a/lib/app/widgets/bantuan_card.dart +++ b/lib/app/widgets/bantuan_card.dart @@ -37,106 +37,167 @@ class BantuanCard extends StatelessWidget { // Tampilan kompak untuk daftar ringkasan if (isCompact) { - return Card( - elevation: 2, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - child: InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(12), - child: Padding( - padding: const EdgeInsets.all(12), - child: Row( - children: [ - Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: (item.isUang == true ? Colors.green : Colors.blue) - .withOpacity(0.1), - borderRadius: BorderRadius.circular(10), - ), - child: Icon( - item.isUang == true - ? Icons.attach_money - : Icons.inventory_2, - color: item.isUang == true ? Colors.green : Colors.blue, - size: 24, - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item.namaPenyaluran ?? item.keterangan ?? 'Bantuan', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 4), - Text( - item.kategoriNama ?? 'Bantuan', - style: TextStyle( - color: Colors.grey.shade700, - fontSize: 14, - ), - ), - const SizedBox(height: 4), - Text( - item.tanggalPenerimaan != null - ? DateFormat('dd MMMM yyyy', 'id_ID') - .format(item.tanggalPenerimaan!) - : '-', - style: TextStyle( - color: Colors.grey.shade600, - fontSize: 12, - ), - ), - ], - ), - ), - const SizedBox(width: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - StatusBadge( - status: item.statusPenerimaan ?? 'BELUMMENERIMA', - fontSize: 10, - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, + return ConstrainedBox( + constraints: const BoxConstraints(minHeight: 100), + child: Card( + elevation: 3, + margin: const EdgeInsets.only(bottom: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: BorderSide( + color: (item.isUang == true ? Colors.green : Colors.blue) + .withOpacity(0.3), + width: 1, + ), + ), + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(12), + child: Padding( + padding: const EdgeInsets.all(12), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, // Ensure max width for main Row + children: [ + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: (item.isUang == true ? Colors.green : Colors.blue) + .withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: + (item.isUang == true ? Colors.green : Colors.blue) + .withOpacity(0.3), + width: 1, ), ), - if (item.statusPenyaluran != null && - item.statusPenyaluran!.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 4), - child: _buildPenyaluranStatusBadge( - item.statusPenyaluran!, - fontSize: 10, + child: Icon( + item.isUang == true + ? Icons.attach_money + : Icons.inventory_2, + color: item.isUang == true ? Colors.green : Colors.blue, + size: 28, + ), + ), + const SizedBox(width: 12), + Expanded( + flex: 3, // Allocate more space to content + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + item.namaPenyaluran ?? item.keterangan ?? 'Bantuan', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + const SizedBox(height: 6), + Text( + item.kategoriNama ?? 'Bantuan', + style: TextStyle( + color: Colors.grey.shade700, + fontSize: 14, + fontWeight: FontWeight.w500, + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + const SizedBox(height: 6), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.calendar_today, + size: 14, + color: Colors.grey.shade600, + ), + const SizedBox(width: 4), + Flexible( + child: Text( + item.tanggalPenerimaan != null + ? DateFormat('dd MMMM yyyy', 'id_ID') + .format(item.tanggalPenerimaan!) + : '-', + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 12, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ], + ), + ), + const SizedBox(width: 8), + Expanded( + flex: 2, // Allocate less space to status/amount + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + StatusBadge( + status: item.statusPenerimaan ?? 'BELUMMENERIMA', + fontSize: 11, padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), ), - ), - const SizedBox(height: 8), - Text( - formattedJumlah, - style: TextStyle( - fontWeight: FontWeight.bold, - color: item.isUang == true ? Colors.green : Colors.blue, - fontSize: 14, - ), + if (item.statusPenyaluran != null && + item.statusPenyaluran!.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 6), + child: StatusBadge( + status: item.statusPenyaluran!, + fontSize: 11, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + ), + ), + const SizedBox(height: 8), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: (item.isUang == true + ? Colors.green + : Colors.blue) + .withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: (item.isUang == true + ? Colors.green + : Colors.blue) + .withOpacity(0.3), + width: 1, + ), + ), + child: Text( + formattedJumlah, + style: TextStyle( + fontWeight: FontWeight.bold, + color: item.isUang == true + ? Colors.green.shade700 + : Colors.blue.shade700, + fontSize: 14, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], ), - ], - ), - ], + ), + ], + ), ), ), ), @@ -144,150 +205,209 @@ class BantuanCard extends StatelessWidget { } // Tampilan detail untuk halaman daftar lengkap - return Card( - margin: const EdgeInsets.only(bottom: 16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 2, - child: InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(12), - child: Padding( - padding: const EdgeInsets.all(16), + return ConstrainedBox( + constraints: const BoxConstraints(minHeight: 200), + child: Card( + margin: const EdgeInsets.only(bottom: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: BorderSide( + color: (item.isUang == true ? Colors.green : Colors.blue) + .withOpacity(0.3), + width: 1, + ), + ), + elevation: 3, + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - item.namaPenyaluran ?? item.keterangan ?? 'Bantuan', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - Wrap( - spacing: 8, - children: [ - StatusBadge(status: item.statusPenyaluran ?? ""), - StatusBadge( - status: item.statusPenerimaan ?? 'BELUMMENERIMA', - ), - ], - ), - ], - ), - if (item.deskripsiPenyaluran != null && - item.deskripsiPenyaluran!.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text( - item.deskripsiPenyaluran!, - style: TextStyle( - color: Colors.grey.shade700, - fontSize: 14, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, + Container( + width: double.infinity, + padding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: (item.isUang == true ? Colors.green : Colors.blue) + .withOpacity(0.1), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(12), + topRight: Radius.circular(12), ), ), - const SizedBox(height: 16), - Row( - children: [ - Icon( - Icons.category, - size: 16, - color: Colors.grey.shade600, - ), - const SizedBox(width: 8), - Text( - item.kategoriNama ?? 'Bantuan', - style: TextStyle( - color: Colors.grey.shade700, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - Icon( - Icons.calendar_today, - size: 16, - color: Colors.grey.shade600, - ), - const SizedBox(width: 8), - Text( - item.tanggalPenerimaan != null - ? DateFormat('dd MMMM yyyy', 'id_ID') - .format(item.tanggalPenerimaan!) - : '-', - style: TextStyle( - color: Colors.grey.shade600, - ), - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - Icon( - Icons.location_on, - size: 16, - color: Colors.grey.shade600, - ), - const SizedBox(width: 8), - Expanded( - child: Text( - item.lokasiPenyaluranNama ?? 'Lokasi tidak tersedia', - style: TextStyle( - color: Colors.grey.shade600, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Row( + children: [ + Icon( + item.isUang == true + ? Icons.attach_money + : Icons.inventory_2, + color: item.isUang == true + ? Colors.green.shade700 + : Colors.blue.shade700, + ), + const SizedBox(width: 8), + Flexible( + child: Text( + item.namaPenyaluran ?? + item.keterangan ?? + 'Bantuan', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: item.isUang == true + ? Colors.green.shade800 + : Colors.blue.shade800, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], ), - maxLines: 1, - overflow: TextOverflow.ellipsis, ), - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - Icon( - item.isUang == true - ? Icons.attach_money - : Icons.inventory_2, - size: 16, - color: Colors.grey.shade600, - ), - const SizedBox(width: 8), - Text( - formattedJumlah, - style: TextStyle( - fontWeight: FontWeight.bold, - color: item.isUang == true ? Colors.green : Colors.blue, + Container( + padding: const EdgeInsets.symmetric( + horizontal: 10, vertical: 5), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Text( + formattedJumlah, + style: TextStyle( + fontWeight: FontWeight.bold, + color: item.isUang == true + ? Colors.green.shade700 + : Colors.blue.shade700, + fontSize: 14, + ), + ), ), - ), - ], + ], + ), ), - const SizedBox(height: 16), - const Divider(height: 1), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - TextButton.icon( - onPressed: onTap, - icon: const Icon(Icons.visibility), - label: const Text('Lihat Detail'), - ), - ], + Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + if (item.statusPenyaluran != null && + item.statusPenyaluran!.isNotEmpty) + StatusBadge( + status: item.statusPenyaluran!, + ), + StatusBadge( + status: item.statusPenerimaan ?? 'BELUMMENERIMA', + ), + ], + ), + if (item.deskripsiPenyaluran != null && + item.deskripsiPenyaluran!.isNotEmpty) + Container( + width: double.infinity, + margin: const EdgeInsets.only(top: 16, bottom: 8), + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Colors.grey.shade200, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Deskripsi:', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.grey.shade700, + ), + ), + const SizedBox(height: 4), + Text( + item.deskripsiPenyaluran!, + style: TextStyle( + color: Colors.grey.shade700, + fontSize: 14, + ), + ), + ], + ), + ), + const SizedBox(height: 16), + Container( + width: double.infinity, + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade200), + ), + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildInfoRow( + Icons.category, + 'Kategori:', + item.kategoriNama ?? 'Bantuan', + ), + const Divider(height: 16), + _buildInfoRow( + Icons.calendar_today, + 'Tanggal:', + item.tanggalPenerimaan != null + ? DateFormat('dd MMMM yyyy', 'id_ID') + .format(item.tanggalPenerimaan!) + : '-', + ), + const Divider(height: 16), + _buildInfoRow( + Icons.location_on, + 'Lokasi:', + item.lokasiPenyaluranNama ?? + 'Lokasi tidak tersedia', + ), + ], + ), + ), + ], + ), + ), + Container( + width: double.infinity, + padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton.icon( + onPressed: onTap, + icon: const Icon(Icons.visibility), + label: const Text('Lihat Detail'), + style: TextButton.styleFrom( + foregroundColor: item.isUang == true + ? Colors.green.shade600 + : Colors.blue.shade600, + ), + ), + ], + ), ), ], ), @@ -296,50 +416,33 @@ class BantuanCard extends StatelessWidget { ); } - // Widget untuk menampilkan badge status penyaluran - Widget _buildPenyaluranStatusBadge( - String status, { - double fontSize = 12, - EdgeInsets padding = - const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - }) { - Color statusColor; - String statusText; - - switch (status.toUpperCase()) { - case 'DIJADWALKAN': - case 'DISETUJUI': - statusColor = Colors.blue; - statusText = 'Dijadwalkan'; - break; - case 'TERLAKSANA': - statusColor = Colors.green; - statusText = 'Terlaksana'; - break; - case 'BATALTERLAKSANA': - statusColor = Colors.red; - statusText = 'Dibatalkan'; - break; - default: - statusColor = Colors.grey; - statusText = status; - } - - return Container( - padding: padding, - decoration: BoxDecoration( - color: statusColor.withOpacity(0.1), - borderRadius: BorderRadius.circular(20), - border: Border.all(color: statusColor), - ), - child: Text( - statusText, - style: TextStyle( - color: statusColor, - fontWeight: FontWeight.bold, - fontSize: fontSize, + Widget _buildInfoRow(IconData icon, String label, String value) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + icon, + size: 18, + color: Colors.grey.shade600, ), - ), + const SizedBox(width: 12), + Text( + label, + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + value, + style: TextStyle( + color: Colors.grey.shade800, + ), + ), + ), + ], ); } }