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 9fe891c..44c7df9 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 f43910d..37946ec 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 79fa7b2..c805443 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 1b52820..abe166b 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/assets/font/DMSans-Bold.ttf b/assets/font/DMSans-Bold.ttf
new file mode 100644
index 0000000..4f5412d
Binary files /dev/null and b/assets/font/DMSans-Bold.ttf differ
diff --git a/assets/font/DMSans-Regular.ttf b/assets/font/DMSans-Regular.ttf
new file mode 100644
index 0000000..07266ae
Binary files /dev/null and b/assets/font/DMSans-Regular.ttf differ
diff --git a/lib/app/data/models/laporan_model.dart b/lib/app/data/models/laporan_model.dart
deleted file mode 100644
index e250f65..0000000
--- a/lib/app/data/models/laporan_model.dart
+++ /dev/null
@@ -1,89 +0,0 @@
-import 'dart:convert';
-
-class LaporanModel {
-  final String? id;
-  final String? judul;
-  final String? deskripsi;
-  final String? jenis; // Contoh: 'PENYALURAN', 'STOK_BANTUAN', 'PENERIMA'
-  final String?
-      referensiId; // ID dari entitas yang dilaporkan (penyaluran, penitipan, dll)
-  final String? status; // Contoh: 'draft', 'final', 'disetujui'
-  final String? petugasId; // Pengguna yang membuat laporan
-  final List<String>? fileUrls; // URL file laporan (PDF, Excel, dll)
-  final DateTime? tanggalMulai;
-  final DateTime? tanggalSelesai;
-  final DateTime? tanggalLaporan;
-  final DateTime? createdAt;
-  final DateTime? updatedAt;
-
-  LaporanModel({
-    this.id,
-    this.judul,
-    this.deskripsi,
-    this.jenis,
-    this.referensiId,
-    this.status,
-    this.petugasId,
-    this.fileUrls,
-    this.tanggalMulai,
-    this.tanggalSelesai,
-    this.tanggalLaporan,
-    this.createdAt,
-    this.updatedAt,
-  });
-
-  factory LaporanModel.fromRawJson(String str) =>
-      LaporanModel.fromJson(json.decode(str));
-
-  String toRawJson() => json.encode(toJson());
-
-  factory LaporanModel.fromJson(Map<String, dynamic> json) => LaporanModel(
-        id: json["id"],
-        judul: json["judul"],
-        deskripsi: json["deskripsi"],
-        jenis: json["jenis"],
-        referensiId: json["referensi_id"],
-        status: json["status"],
-        petugasId: json["petugas_id"] ?? json["user_id"],
-        fileUrls: json["file_urls"] == null
-            ? null
-            : List<String>.from(json["file_urls"].map((x) => x)),
-        tanggalMulai: json["tanggal_mulai"] != null
-            ? DateTime.parse(json["tanggal_mulai"])
-            : json["periode_awal"] != null
-                ? DateTime.parse(json["periode_awal"])
-                : null,
-        tanggalSelesai: json["tanggal_selesai"] != null
-            ? DateTime.parse(json["tanggal_selesai"])
-            : json["periode_akhir"] != null
-                ? DateTime.parse(json["periode_akhir"])
-                : null,
-        tanggalLaporan: json["tanggal_laporan"] != null
-            ? DateTime.parse(json["tanggal_laporan"])
-            : null,
-        createdAt: json["created_at"] != null
-            ? DateTime.parse(json["created_at"])
-            : null,
-        updatedAt: json["updated_at"] != null
-            ? DateTime.parse(json["updated_at"])
-            : null,
-      );
-
-  Map<String, dynamic> toJson() => {
-        "id": id,
-        "judul": judul,
-        "deskripsi": deskripsi,
-        "jenis": jenis,
-        "referensi_id": referensiId,
-        "status": status,
-        "petugas_id": petugasId,
-        "file_urls": fileUrls == null
-            ? null
-            : List<dynamic>.from(fileUrls!.map((x) => x)),
-        "tanggal_mulai": tanggalMulai?.toIso8601String(),
-        "tanggal_selesai": tanggalSelesai?.toIso8601String(),
-        "tanggal_laporan": tanggalLaporan?.toIso8601String(),
-        "created_at": createdAt?.toIso8601String(),
-        "updated_at": updatedAt?.toIso8601String(),
-      };
-}
diff --git a/lib/app/data/models/laporan_penyaluran_model.dart b/lib/app/data/models/laporan_penyaluran_model.dart
new file mode 100644
index 0000000..db1a7bb
--- /dev/null
+++ b/lib/app/data/models/laporan_penyaluran_model.dart
@@ -0,0 +1,61 @@
+import 'dart:convert';
+
+class LaporanPenyaluranModel {
+  final String? id;
+  final String penyaluranBantuanId;
+  final String judul;
+  final String? dokumentasiUrl;
+  final String? beritaAcaraUrl;
+  final DateTime? tanggalLaporan;
+  final String? status;
+  final DateTime? createdAt;
+  final DateTime? updatedAt;
+
+  LaporanPenyaluranModel({
+    this.id,
+    required this.penyaluranBantuanId,
+    required this.judul,
+    this.dokumentasiUrl,
+    this.beritaAcaraUrl,
+    this.tanggalLaporan,
+    this.status,
+    this.createdAt,
+    this.updatedAt,
+  });
+
+  factory LaporanPenyaluranModel.fromRawJson(String str) =>
+      LaporanPenyaluranModel.fromJson(json.decode(str));
+
+  String toRawJson() => json.encode(toJson());
+
+  factory LaporanPenyaluranModel.fromJson(Map<String, dynamic> json) =>
+      LaporanPenyaluranModel(
+        id: json["id"],
+        penyaluranBantuanId: json["penyaluran_bantuan_id"],
+        judul: json["judul"],
+        dokumentasiUrl: json["dokumentasi_url"],
+        beritaAcaraUrl: json["berita_acara_url"],
+        tanggalLaporan: json["tanggal_laporan"] != null
+            ? DateTime.parse(json["tanggal_laporan"]).toUtc()
+            : null,
+        status: json["status"],
+        createdAt: json["created_at"] != null
+            ? DateTime.parse(json["created_at"]).toUtc()
+            : null,
+        updatedAt: json["updated_at"] != null
+            ? DateTime.parse(json["updated_at"]).toUtc()
+            : null,
+      );
+
+  Map<String, dynamic> toJson() => {
+        "id": id,
+        "penyaluran_bantuan_id": penyaluranBantuanId,
+        "judul": judul,
+        "dokumentasi_url": dokumentasiUrl,
+        "berita_acara_url": beritaAcaraUrl,
+        "tanggal_laporan": tanggalLaporan?.toUtc().toIso8601String(),
+        "status": status,
+        "created_at": createdAt?.toUtc().toIso8601String(),
+        "updated_at": updatedAt?.toUtc().toIso8601String(),
+      };
+}
diff --git a/lib/app/modules/laporan_penyaluran/bindings/laporan_penyaluran_binding.dart b/lib/app/modules/laporan_penyaluran/bindings/laporan_penyaluran_binding.dart
new file mode 100644
index 0000000..d6e4ff0
--- /dev/null
+++ b/lib/app/modules/laporan_penyaluran/bindings/laporan_penyaluran_binding.dart
@@ -0,0 +1,11 @@
+import 'package:get/get.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/controllers/laporan_penyaluran_controller.dart';
+
+class LaporanPenyaluranBinding extends Bindings {
+  @override
+  void dependencies() {
+    Get.lazyPut<LaporanPenyaluranController>(
+      () => LaporanPenyaluranController(),
+    );
+  }
+}
diff --git a/lib/app/modules/laporan_penyaluran/controllers/laporan_penyaluran_controller.dart b/lib/app/modules/laporan_penyaluran/controllers/laporan_penyaluran_controller.dart
new file mode 100644
index 0000000..2c378d4
--- /dev/null
+++ b/lib/app/modules/laporan_penyaluran/controllers/laporan_penyaluran_controller.dart
@@ -0,0 +1,1181 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:penyaluran_app/app/data/models/laporan_penyaluran_model.dart';
+import 'package:penyaluran_app/app/data/models/penerima_penyaluran_model.dart';
+import 'package:penyaluran_app/app/data/models/penyaluran_bantuan_model.dart';
+import 'package:penyaluran_app/app/modules/auth/controllers/auth_controller.dart';
+import 'package:penyaluran_app/app/services/supabase_service.dart';
+import 'package:pdf/pdf.dart';
+import 'package:pdf/widgets.dart' as pw;
+import 'package:path_provider/path_provider.dart';
+import 'dart:io';
+import 'package:open_file/open_file.dart';
+import 'package:flutter/services.dart';
+import 'package:intl/intl.dart';
+import 'package:http/http.dart' as http;
+import 'package:penyaluran_app/app/utils/date_time_helper.dart';
+
+class LaporanPenyaluranController extends GetxController {
+  final AuthController _authController = Get.find<AuthController>();
+  final SupabaseService _supabaseService = SupabaseService.to;
+
+  // Data
+  final RxList<LaporanPenyaluranModel> daftarLaporan =
+      <LaporanPenyaluranModel>[].obs;
+  final RxList<PenyaluranBantuanModel> penyaluranTanpaLaporan =
+      <PenyaluranBantuanModel>[].obs;
+  final Rx<LaporanPenyaluranModel?> selectedLaporan =
+      Rx<LaporanPenyaluranModel?>(null);
+  final Rx<PenyaluranBantuanModel?> selectedPenyaluran =
+      Rx<PenyaluranBantuanModel?>(null);
+  final RxList<PenerimaPenyaluranModel> daftarPenerima =
+      <PenerimaPenyaluranModel>[].obs;
+  final RxMap<String, double> stokBantuanUsage = RxMap<String, double>();
+  final RxMap<String, dynamic> lokasiPenyaluran = RxMap<String, dynamic>();
+  final RxMap<String, dynamic> desaData = RxMap<String, dynamic>();
+  final RxMap<String, dynamic> kategoriBantuan = RxMap<String, dynamic>();
+
+  // Form controllers
+  final TextEditingController judulController = TextEditingController();
+
+  // File controllers untuk dokumentasi dan berita acara
+  final RxString dokumentasiPath = RxString('');
+  final RxString beritaAcaraPath = RxString('');
+  final RxBool isDokumentasiUploading = false.obs;
+  final RxBool isBeritaAcaraUploading = false.obs;
+
+  // Loading states
+  final RxBool isLoading = false.obs;
+  final RxBool isSaving = false.obs;
+  final RxBool isExporting = false.obs;
+
+  // Filter status
+  final RxString filterStatus = 'SEMUA'.obs;
+
+  // Getter untuk data user
+  get user => _authController.user;
+  String get role => user?.role ?? 'WARGA';
+
+  @override
+  void onInit() {
+    super.onInit();
+    fetchLaporan();
+  }
+
+  @override
+  void onClose() {
+    judulController.dispose();
+    super.onClose();
+  }
+
+  // Reset form untuk pembuatan laporan baru
+  void resetForm() {
+    judulController.clear();
+    dokumentasiPath.value = '';
+    beritaAcaraPath.value = '';
+    isDokumentasiUploading.value = false;
+    isBeritaAcaraUploading.value = false;
+  }
+
+  // Mengambil data semua laporan penyaluran
+  Future<void> fetchLaporan() async {
+    isLoading.value = true;
+    try {
+      final response = await _supabaseService.client
+          .from('laporan_penyaluran')
+          .select('*')
+          .order('created_at', ascending: false);
+
+      daftarLaporan.value = (response as List<dynamic>)
+          .map((item) => LaporanPenyaluranModel.fromJson(item))
+          .toList();
+
+      await fetchPenyaluranTanpaLaporan();
+    } catch (e) {
+      print('Error fetching laporan: $e');
+      Get.snackbar(
+        'Error',
+        'Gagal memuat data laporan',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+      );
+    } finally {
+      isLoading.value = false;
+    }
+  }
+
+  // Mengambil data penyaluran yang belum memiliki laporan
+  Future<void> fetchPenyaluranTanpaLaporan() async {
+    try {
+      // Ambil semua penyaluran dengan status TERLAKSANA
+      final response = await _supabaseService.client
+          .from('penyaluran_bantuan')
+          .select('*')
+          .eq('status', 'TERLAKSANA')
+          .order('tanggal_selesai', ascending: false);
+
+      final allPenyaluran = (response as List<dynamic>)
+          .map((item) => PenyaluranBantuanModel.fromJson(item))
+          .toList();
+
+      // Filter penyaluran yang belum memiliki laporan
+      final penyaluranIds =
+          daftarLaporan.map((e) => e.penyaluranBantuanId).toList();
+      penyaluranTanpaLaporan.value = allPenyaluran
+          .where((penyaluran) => !penyaluranIds.contains(penyaluran.id))
+          .toList();
+    } catch (e) {
+      print('Error fetching penyaluran tanpa laporan: $e');
+    }
+  }
+
+  // Mendapatkan detail laporan berdasarkan ID
+  Future<void> fetchLaporanDetail(String laporanId) async {
+    isLoading.value = true;
+    try {
+      final response = await _supabaseService.client
+          .from('laporan_penyaluran')
+          .select('*')
+          .eq('id', laporanId)
+          .single();
+
+      selectedLaporan.value = LaporanPenyaluranModel.fromJson(response);
+
+      // Ambil data penyaluran terkait
+      await fetchPenyaluranDetail(selectedLaporan.value!.penyaluranBantuanId);
+    } catch (e) {
+      print('Error fetching laporan detail: $e');
+      Get.snackbar(
+        'Error',
+        'Gagal memuat detail laporan',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+      );
+    } finally {
+      isLoading.value = false;
+    }
+  }
+
+  // Mendapatkan detail penyaluran berdasarkan ID
+  Future<void> fetchPenyaluranDetail(String penyaluranId) async {
+    try {
+      final response = await _supabaseService.client
+          .from('penyaluran_bantuan')
+          .select('*')
+          .eq('id', penyaluranId)
+          .single();
+
+      selectedPenyaluran.value = PenyaluranBantuanModel.fromJson(response);
+
+      // Ambil data penerima terkait
+      await fetchPenerimaPenyaluran(penyaluranId);
+
+      // Ambil data lokasi penyaluran
+      if (selectedPenyaluran.value?.lokasiPenyaluranId != null) {
+        await fetchLokasiPenyaluran(
+            selectedPenyaluran.value!.lokasiPenyaluranId!);
+      }
+
+      // Hitung penggunaan stok bantuan
+      await calculateStokBantuanUsage(penyaluranId);
+    } catch (e) {
+      print('Error fetching penyaluran detail: $e');
+    }
+  }
+
+  // Mendapatkan daftar penerima penyaluran
+  Future<void> fetchPenerimaPenyaluran(String penyaluranId) async {
+    try {
+      final response = await _supabaseService.client
+          .from('penerima_penyaluran')
+          .select('*, warga(*), stok_bantuan(*)')
+          .eq('penyaluran_bantuan_id', penyaluranId);
+
+      daftarPenerima.value = (response as List<dynamic>)
+          .map((item) => PenerimaPenyaluranModel.fromJson(item))
+          .toList();
+    } catch (e) {
+      print('Error fetching penerima penyaluran: $e');
+    }
+  }
+
+  // Mendapatkan data lokasi penyaluran
+  Future<void> fetchLokasiPenyaluran(String lokasiId) async {
+    try {
+      final response = await _supabaseService.client
+          .from('lokasi_penyaluran')
+          .select('*, desa_id')
+          .eq('id', lokasiId)
+          .single();
+
+      lokasiPenyaluran.value = response;
+
+      // Ambil data desa jika ada desa_id
+      if (lokasiPenyaluran['desa_id'] != null) {
+        await fetchDesaData(lokasiPenyaluran['desa_id']);
+      }
+    } catch (e) {
+      print('Error fetching lokasi penyaluran: $e');
+    }
+  }
+
+  // Mendapatkan data desa
+  Future<void> fetchDesaData(String desaId) async {
+    try {
+      final response = await _supabaseService.client
+          .from('desa')
+          .select('*, kecamatan, kabupaten, provinsi')
+          .eq('id', desaId)
+          .single();
+
+      desaData.value = response;
+    } catch (e) {
+      print('Error fetching desa data: $e');
+    }
+  }
+
+  // Mendapatkan data kategori bantuan berdasarkan ID
+  Future<void> fetchKategoriBantuan(String kategoriId) async {
+    try {
+      final response = await _supabaseService.client
+          .from('kategori_bantuan')
+          .select('*')
+          .eq('id', kategoriId)
+          .single();
+
+      kategoriBantuan.value = response;
+    } catch (e) {
+      print('Error fetching kategori bantuan: $e');
+    }
+  }
+
+  // Menghitung penggunaan stok bantuan
+  Future<void> calculateStokBantuanUsage(String penyaluranId) async {
+    try {
+      // Reset stok usage
+      stokBantuanUsage.clear();
+
+      // Group by stok_bantuan_id and calculate total usage
+      for (var penerima in daftarPenerima) {
+        if (penerima.stokBantuanId != null && penerima.jumlahBantuan != null) {
+          final stokId = penerima.stokBantuanId!;
+          final amount = penerima.jumlahBantuan!;
+
+          if (stokBantuanUsage.containsKey(stokId)) {
+            stokBantuanUsage[stokId] = stokBantuanUsage[stokId]! + amount;
+          } else {
+            stokBantuanUsage[stokId] = amount;
+          }
+
+          // Dapatkan kategori bantuan jika stok bantuan ini memilikinya
+          if (penerima.stokBantuan != null &&
+              penerima.stokBantuan!['kategori_bantuan_id'] != null &&
+              kategoriBantuan.isEmpty) {
+            await fetchKategoriBantuan(
+                penerima.stokBantuan!['kategori_bantuan_id']);
+          }
+        }
+      }
+    } catch (e) {
+      print('Error calculating stok bantuan usage: $e');
+    }
+  }
+
+  // Set form untuk edit
+  void setFormForEdit(LaporanPenyaluranModel laporan) {
+    judulController.text = laporan.judul;
+
+    // Reset dokumentasi dan berita acara path agar tampil dari URL yang sudah ada
+    dokumentasiPath.value = '';
+    beritaAcaraPath.value = '';
+  }
+
+  // Validasi form
+  bool validateForm() {
+    if (judulController.text.isEmpty) {
+      Get.snackbar(
+        'Validasi Gagal',
+        'Judul laporan tidak boleh kosong',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+      );
+      return false;
+    }
+    return true;
+  }
+
+  // Upload dokumentasi
+  Future<String?> uploadDokumentasi(File file) async {
+    isDokumentasiUploading.value = true;
+    try {
+      final fileExt = file.path.split('.').last;
+      final fileName =
+          'dokumentasi_${DateTime.now().millisecondsSinceEpoch}.$fileExt';
+      final filePath = 'dokumentasi/$fileName';
+
+      final response = await _supabaseService.client.storage
+          .from('laporan_penyaluran')
+          .upload(filePath, file);
+
+      // Dapatkan URL publik
+      final String publicUrl = _supabaseService.client.storage
+          .from('laporan_penyaluran')
+          .getPublicUrl(filePath);
+
+      return publicUrl;
+    } catch (e) {
+      print('Error uploading dokumentasi: $e');
+      Get.snackbar(
+        'Error',
+        'Gagal mengunggah dokumentasi',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+      );
+      return null;
+    } finally {
+      isDokumentasiUploading.value = false;
+    }
+  }
+
+  // Upload berita acara
+  Future<String?> uploadBeritaAcara(File file) async {
+    isBeritaAcaraUploading.value = true;
+    try {
+      final fileExt = file.path.split('.').last;
+      final fileName =
+          'berita_acara_${DateTime.now().millisecondsSinceEpoch}.$fileExt';
+      final filePath = 'berita_acara/$fileName';
+
+      final response = await _supabaseService.client.storage
+          .from('laporan_penyaluran')
+          .upload(filePath, file);
+
+      // Dapatkan URL publik
+      final String publicUrl = _supabaseService.client.storage
+          .from('laporan_penyaluran')
+          .getPublicUrl(filePath);
+
+      return publicUrl;
+    } catch (e) {
+      print('Error uploading berita acara: $e');
+      Get.snackbar(
+        'Error',
+        'Gagal mengunggah berita acara',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+      );
+      return null;
+    } finally {
+      isBeritaAcaraUploading.value = false;
+    }
+  }
+
+  // Menyimpan laporan baru
+  Future<void> saveLaporan(String penyaluranId) async {
+    if (!validateForm()) return;
+
+    isSaving.value = true;
+    try {
+      // Upload dokumentasi jika ada
+      String? dokumentasiUrl;
+      if (dokumentasiPath.isNotEmpty) {
+        dokumentasiUrl = await uploadDokumentasi(File(dokumentasiPath.value));
+      }
+
+      // Upload berita acara jika ada
+      String? beritaAcaraUrl;
+      if (beritaAcaraPath.isNotEmpty) {
+        beritaAcaraUrl = await uploadBeritaAcara(File(beritaAcaraPath.value));
+      }
+
+      final data = {
+        'penyaluran_bantuan_id': penyaluranId,
+        'judul': judulController.text,
+        'tanggal_laporan': DateTime.now().toUtc().toIso8601String(),
+        'status': 'DRAFT',
+        if (dokumentasiUrl != null) 'dokumentasi_url': dokumentasiUrl,
+        if (beritaAcaraUrl != null) 'berita_acara_url': beritaAcaraUrl,
+      };
+
+      final response = await _supabaseService.client
+          .from('laporan_penyaluran')
+          .insert(data)
+          .select()
+          .single();
+
+      Get.snackbar(
+        'Sukses',
+        'Laporan berhasil disimpan',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.green,
+        colorText: Colors.white,
+      );
+
+      resetForm();
+      Get.back();
+      await fetchLaporan();
+    } catch (e) {
+      print('Error saving laporan: $e');
+      Get.snackbar(
+        'Error',
+        'Gagal menyimpan laporan',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+      );
+    } finally {
+      isSaving.value = false;
+    }
+  }
+
+  // Update laporan
+  Future<void> updateLaporan(String laporanId) async {
+    if (!validateForm()) return;
+
+    isSaving.value = true;
+    try {
+      // Upload dokumentasi jika ada perubahan
+      String? dokumentasiUrl;
+      if (dokumentasiPath.isNotEmpty) {
+        dokumentasiUrl = await uploadDokumentasi(File(dokumentasiPath.value));
+      }
+
+      // Upload berita acara jika ada perubahan
+      String? beritaAcaraUrl;
+      if (beritaAcaraPath.isNotEmpty) {
+        beritaAcaraUrl = await uploadBeritaAcara(File(beritaAcaraPath.value));
+      }
+
+      final data = {
+        'judul': judulController.text,
+        'updated_at': DateTime.now().toUtc().toIso8601String(),
+        if (dokumentasiUrl != null) 'dokumentasi_url': dokumentasiUrl,
+        if (beritaAcaraUrl != null) 'berita_acara_url': beritaAcaraUrl,
+      };
+
+      await _supabaseService.client
+          .from('laporan_penyaluran')
+          .update(data)
+          .eq('id', laporanId);
+
+      Get.snackbar(
+        'Sukses',
+        'Laporan berhasil diperbarui',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.green,
+        colorText: Colors.white,
+      );
+
+      Get.back();
+      await fetchLaporanDetail(laporanId);
+    } catch (e) {
+      print('Error updating laporan: $e');
+      Get.snackbar(
+        'Error',
+        'Gagal memperbarui laporan',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+      );
+    } finally {
+      isSaving.value = false;
+    }
+  }
+
+  // Finalisasi laporan
+  Future<void> finalizeLaporan(String laporanId) async {
+    try {
+      await _supabaseService.client.from('laporan_penyaluran').update({
+        'status': 'FINAL',
+        'updated_at': DateTime.now().toUtc().toIso8601String(),
+      }).eq('id', laporanId);
+
+      Get.snackbar(
+        'Sukses',
+        'Laporan berhasil difinalisasi',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.green,
+        colorText: Colors.white,
+      );
+
+      await fetchLaporanDetail(laporanId);
+    } catch (e) {
+      print('Error finalizing laporan: $e');
+      Get.snackbar(
+        'Error',
+        'Gagal memfinalisasi laporan',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+      );
+    }
+  }
+
+  // Hapus laporan
+  Future<void> deleteLaporan(String laporanId) async {
+    try {
+      await _supabaseService.client
+          .from('laporan_penyaluran')
+          .delete()
+          .eq('id', laporanId);
+
+      Get.snackbar(
+        'Sukses',
+        'Laporan berhasil dihapus',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.green,
+        colorText: Colors.white,
+      );
+
+      Get.back();
+      await fetchLaporan();
+    } catch (e) {
+      print('Error deleting laporan: $e');
+      Get.snackbar(
+        'Error',
+        'Gagal menghapus laporan',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+      );
+    }
+  }
+
+  // Export laporan ke PDF
+  Future<void> exportToPdf(
+      LaporanPenyaluranModel laporan, PenyaluranBantuanModel penyaluran) async {
+    isExporting.value = true;
+    try {
+      // Buat dokumen PDF
+      final pdf = pw.Document();
+
+      // Load font
+      final font = await rootBundle.load("assets/font/DMSans-Regular.ttf");
+      final fontBold = await rootBundle.load("assets/font/DMSans-Bold.ttf");
+      final ttf = pw.Font.ttf(font);
+      final ttfBold = pw.Font.ttf(fontBold);
+
+      // Load logo - tidak perlu menampilkan error jika logo tidak ada
+      pw.MemoryImage? logoImage;
+      try {
+        final logoBytes = await rootBundle.load('assets/img/logo.png');
+        logoImage = pw.MemoryImage(logoBytes.buffer.asUint8List());
+      } catch (e) {
+        // Logo tidak ditemukan - tidak perlu print error
+        // Cukup terapkan null handling saat menggunakan logoImage
+      }
+
+      // Coba unduh gambar dokumentasi menggunakan http statis (bukan dinamis)
+      pw.MemoryImage? dokumentasiImage;
+      if (laporan.dokumentasiUrl != null &&
+          laporan.dokumentasiUrl!.isNotEmpty) {
+        try {
+          // Gunakan http package secara langsung (pastikan sudah ditambahkan di pubspec.yaml)
+          // import 'package:http/http.dart' as http; (tambahkan di bagian atas file)
+          final response = await http.get(Uri.parse(laporan.dokumentasiUrl!));
+          if (response.statusCode == 200) {
+            dokumentasiImage = pw.MemoryImage(response.bodyBytes);
+          }
+        } catch (e) {
+          // Error unduh gambar - tidak perlu mencoba import dinamis
+          print('Tidak dapat mengunduh gambar dokumentasi: $e');
+        }
+      }
+
+      // Tambahkan halaman
+      pdf.addPage(
+        pw.MultiPage(
+          pageFormat: PdfPageFormat.a4,
+          margin: const pw.EdgeInsets.all(20),
+          header: (pw.Context context) {
+            return pw.Column(
+              children: [
+                pw.Row(
+                  mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
+                  children: [
+                    logoImage != null
+                        ? pw.Image(logoImage, width: 60, height: 60)
+                        : pw.SizedBox(width: 60),
+                    pw.Column(
+                      crossAxisAlignment: pw.CrossAxisAlignment.end,
+                      children: [
+                        pw.Text('LAPORAN PENYALURAN BANTUAN',
+                            style: pw.TextStyle(
+                                font: ttfBold,
+                                fontSize: 12,
+                                color: PdfColors.blue900)),
+                        pw.Text(
+                          'Tanggal: ${DateFormat('dd MMMM yyyy').format(DateTime.now())}',
+                          style: pw.TextStyle(font: ttf, fontSize: 10),
+                        ),
+                      ],
+                    ),
+                  ],
+                ),
+                pw.SizedBox(height: 5),
+                pw.Divider(color: PdfColors.blue900, thickness: 2),
+              ],
+            );
+          },
+          footer: (pw.Context context) {
+            return pw.Column(
+              children: [
+                pw.Divider(color: PdfColors.grey400),
+                pw.SizedBox(height: 5),
+                pw.Row(
+                  mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
+                  children: [
+                    pw.Text(
+                      'Laporan Penyaluran | ${laporan.judul}',
+                      style: pw.TextStyle(
+                          font: ttf, fontSize: 8, color: PdfColors.grey600),
+                    ),
+                    pw.Text(
+                      'Halaman ${context.pageNumber} dari ${context.pagesCount}',
+                      style: pw.TextStyle(
+                          font: ttf, fontSize: 8, color: PdfColors.grey600),
+                    ),
+                  ],
+                ),
+              ],
+            );
+          },
+          build: (pw.Context context) {
+            return [
+              // Judul Utama
+              pw.Center(
+                child: pw.Column(
+                  children: [
+                    pw.Text(
+                      laporan.judul.toUpperCase(),
+                      style: pw.TextStyle(
+                        font: ttfBold,
+                        fontSize: 16,
+                        color: PdfColors.blue900,
+                      ),
+                      textAlign: pw.TextAlign.center,
+                    ),
+                    pw.SizedBox(height: 5),
+                    pw.Text(
+                      penyaluran.nama ?? 'Penyaluran Bantuan',
+                      style: pw.TextStyle(
+                        font: ttf,
+                        fontSize: 12,
+                        color: PdfColors.grey700,
+                      ),
+                      textAlign: pw.TextAlign.center,
+                    ),
+                  ],
+                ),
+              ),
+              pw.SizedBox(height: 20),
+
+              // Informasi Laporan
+              _buildPdfSection(
+                'INFORMASI LAPORAN',
+                [
+                  _buildPdfRow('Judul Laporan', laporan.judul, ttf, ttfBold),
+                  _buildPdfRow(
+                      'Tanggal Laporan',
+                      laporan.tanggalLaporan != null
+                          ? DateTimeHelper.formatDateTime(
+                              laporan.tanggalLaporan!)
+                          : '-',
+                      ttf,
+                      ttfBold),
+                  _buildPdfRow(
+                      'Status', laporan.status ?? 'DRAFT', ttf, ttfBold),
+                ],
+                ttfBold,
+                PdfColors.blue900,
+              ),
+
+              pw.SizedBox(height: 15),
+
+              // Informasi Penyaluran
+              _buildPdfSection(
+                'INFORMASI PENYALURAN',
+                [
+                  _buildPdfRow(
+                      'Nama Penyaluran', penyaluran.nama ?? '-', ttf, ttfBold),
+                  _buildPdfRow(
+                      'Tanggal Penyaluran',
+                      penyaluran.tanggalPenyaluran != null
+                          ? DateTimeHelper.formatDateTime(
+                              penyaluran.tanggalPenyaluran!)
+                          : '-',
+                      ttf,
+                      ttfBold),
+                  _buildPdfRow(
+                      'Tanggal Selesai',
+                      penyaluran.tanggalSelesai != null
+                          ? DateTimeHelper.formatDateTime(
+                              penyaluran.tanggalSelesai!)
+                          : '-',
+                      ttf,
+                      ttfBold),
+                  _buildPdfRow('Jumlah Penerima',
+                      '${penyaluran.jumlahPenerima ?? 0} orang', ttf, ttfBold),
+                  _buildPdfRow('Status Penyaluran', penyaluran.status ?? '-',
+                      ttf, ttfBold),
+                  if (penyaluran.deskripsi != null &&
+                      penyaluran.deskripsi!.isNotEmpty) ...[
+                    pw.SizedBox(height: 10),
+                    pw.Text('Deskripsi Penyaluran:',
+                        style: pw.TextStyle(font: ttfBold)),
+                    pw.SizedBox(height: 3),
+                    pw.Container(
+                      padding: const pw.EdgeInsets.all(8),
+                      decoration: pw.BoxDecoration(
+                        color: PdfColors.grey100,
+                        borderRadius: pw.BorderRadius.circular(4),
+                      ),
+                      child: pw.Text(penyaluran.deskripsi!,
+                          style: pw.TextStyle(font: ttf, fontSize: 10)),
+                    ),
+                  ],
+                ],
+                ttfBold,
+                PdfColors.blue900,
+              ),
+
+              // Informasi Lokasi Penyaluran
+              if (lokasiPenyaluran.isNotEmpty) ...[
+                pw.SizedBox(height: 15),
+                _buildPdfSection(
+                  'LOKASI PENYALURAN',
+                  [
+                    _buildPdfRow('Nama Lokasi', lokasiPenyaluran['nama'] ?? '-',
+                        ttf, ttfBold),
+                    _buildPdfRow(
+                        'Alamat',
+                        lokasiPenyaluran['alamat_lengkap'] ?? '-',
+                        ttf,
+                        ttfBold),
+                    if (desaData.isNotEmpty) ...[
+                      _buildPdfRow('Desa/Kelurahan', desaData['nama'] ?? '-',
+                          ttf, ttfBold),
+                      _buildPdfRow('Kecamatan', desaData['kecamatan'] ?? '-',
+                          ttf, ttfBold),
+                      _buildPdfRow('Kabupaten/Kota',
+                          desaData['kabupaten'] ?? '-', ttf, ttfBold),
+                      _buildPdfRow('Provinsi', desaData['provinsi'] ?? '-', ttf,
+                          ttfBold),
+                    ] else ...[
+                      _buildPdfRow('Kecamatan',
+                          lokasiPenyaluran['kecamatan'] ?? '-', ttf, ttfBold),
+                      _buildPdfRow(
+                          'Kelurahan/Desa',
+                          lokasiPenyaluran['kelurahan_desa'] ?? '-',
+                          ttf,
+                          ttfBold),
+                    ],
+                    if (lokasiPenyaluran['keterangan'] != null &&
+                        lokasiPenyaluran['keterangan']
+                            .toString()
+                            .isNotEmpty) ...[
+                      pw.SizedBox(height: 10),
+                      pw.Text('Keterangan Lokasi:',
+                          style: pw.TextStyle(font: ttfBold)),
+                      pw.SizedBox(height: 3),
+                      pw.Container(
+                        padding: const pw.EdgeInsets.all(8),
+                        decoration: pw.BoxDecoration(
+                          color: PdfColors.grey100,
+                          borderRadius: pw.BorderRadius.circular(4),
+                        ),
+                        child: pw.Text(lokasiPenyaluran['keterangan'],
+                            style: pw.TextStyle(font: ttf, fontSize: 10)),
+                      ),
+                    ],
+                  ],
+                  ttfBold,
+                  PdfColors.blue900,
+                ),
+              ],
+
+              // Informasi Stok Bantuan
+              pw.SizedBox(height: 15),
+              pw.NewPage(),
+              if (stokBantuanUsage.isNotEmpty) ...[
+                _buildPdfSection(
+                  'STOK BANTUAN YANG DIGUNAKAN',
+                  [
+                    // Informasi kategori bantuan jika tersedia
+                    if (kategoriBantuan.isNotEmpty) ...[
+                      pw.Container(
+                        padding: const pw.EdgeInsets.all(8),
+                        decoration: pw.BoxDecoration(
+                          color: PdfColors.grey100,
+                          border: pw.Border.all(color: PdfColors.grey300),
+                          borderRadius: pw.BorderRadius.circular(5),
+                        ),
+                        child: pw.Column(
+                          crossAxisAlignment: pw.CrossAxisAlignment.start,
+                          children: [
+                            pw.Text(
+                              'Kategori Bantuan: ${kategoriBantuan['nama'] ?? 'Tidak Diketahui'}',
+                              style: pw.TextStyle(
+                                font: ttfBold,
+                                fontSize: 12,
+                              ),
+                            ),
+                            if (kategoriBantuan['deskripsi'] != null) ...[
+                              pw.SizedBox(height: 3),
+                              pw.Text(
+                                kategoriBantuan['deskripsi'],
+                                style: pw.TextStyle(font: ttf, fontSize: 10),
+                              ),
+                            ],
+                          ],
+                        ),
+                      ),
+                      pw.SizedBox(height: 10),
+                    ],
+                    pw.Table(
+                      border: pw.TableBorder.all(
+                        color: PdfColors.blue200,
+                        width: 0.5,
+                      ),
+                      children: [
+                        // Header
+                        pw.TableRow(
+                          decoration: pw.BoxDecoration(
+                            color: PdfColors.blue50,
+                          ),
+                          children: [
+                            _buildPdfTableCell('Nama Bantuan', ttfBold,
+                                isHeader: true, color: PdfColors.blue900),
+                            _buildPdfTableCell('Jumlah Digunakan', ttfBold,
+                                isHeader: true,
+                                align: pw.TextAlign.center,
+                                color: PdfColors.blue900),
+                          ],
+                        ),
+                        // Data
+                        ...stokBantuanUsage.entries.map((entry) {
+                          final stokId = entry.key;
+                          final jumlah = entry.value;
+
+                          // Find stok bantuan details
+                          final stokBantuan = daftarPenerima
+                              .firstWhere((p) => p.stokBantuanId == stokId,
+                                  orElse: () => PenerimaPenyaluranModel())
+                              ?.stokBantuan;
+
+                          if (stokBantuan == null)
+                            return pw.TableRow(children: [
+                              _buildPdfTableCell('-', ttf),
+                              _buildPdfTableCell('-', ttf),
+                            ]);
+
+                          final isUang = stokBantuan['is_uang'] == true;
+                          final formattedJumlah = isUang
+                              ? 'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(jumlah)}'
+                              : '$jumlah ${stokBantuan['satuan'] ?? ''}';
+
+                          return pw.TableRow(
+                            children: [
+                              _buildPdfTableCell(
+                                  stokBantuan['nama'] ?? '-', ttf),
+                              _buildPdfTableCell(formattedJumlah, ttf,
+                                  align: pw.TextAlign.center),
+                            ],
+                          );
+                        }).toList(),
+                      ],
+                    ),
+                  ],
+                  ttfBold,
+                  PdfColors.blue900,
+                ),
+              ],
+
+              // Daftar Penerima
+              if (daftarPenerima.isNotEmpty) ...[
+                pw.SizedBox(height: 15),
+                _buildPdfSection(
+                  'DAFTAR PENERIMA BANTUAN',
+                  [
+                    pw.Table(
+                      border: pw.TableBorder.all(
+                        color: PdfColors.blue200,
+                        width: 0.5,
+                      ),
+                      children: [
+                        // Header
+                        pw.TableRow(
+                          decoration: pw.BoxDecoration(
+                            color: PdfColors.blue50,
+                          ),
+                          children: [
+                            //nik
+                            _buildPdfTableCell('NIK', ttfBold,
+                                isHeader: true, color: PdfColors.blue900),
+                            _buildPdfTableCell('Nama Penerima', ttfBold,
+                                isHeader: true, color: PdfColors.blue900),
+
+                            _buildPdfTableCell('Jumlah', ttfBold,
+                                isHeader: true,
+                                align: pw.TextAlign.center,
+                                color: PdfColors.blue900),
+                            _buildPdfTableCell('Satuan', ttfBold,
+                                isHeader: true,
+                                align: pw.TextAlign.center,
+                                color: PdfColors.blue900),
+                            _buildPdfTableCell('Status', ttfBold,
+                                isHeader: true,
+                                align: pw.TextAlign.center,
+                                color: PdfColors.blue900),
+                          ],
+                        ),
+                        // Data
+                        ...daftarPenerima.map((penerima) {
+                          final nik = penerima.warga != null
+                              ? penerima.warga!['nik'] ?? '-'
+                              : '-';
+                          final wargaNama = penerima.warga != null
+                              ? penerima.warga!['nama_lengkap'] ?? '-'
+                              : '-';
+
+                          final jumlah = penerima.jumlahBantuan != null
+                              ? '${penerima.jumlahBantuan} ${penerima.satuan ?? ''}'
+                              : '-';
+
+                          return pw.TableRow(
+                            children: [
+                              _buildPdfTableCell(nik, ttf),
+                              _buildPdfTableCell(wargaNama, ttf),
+                              _buildPdfTableCell(jumlah, ttf,
+                                  align: pw.TextAlign.center),
+                              _buildPdfTableCell(penerima.satuan ?? '-', ttf,
+                                  align: pw.TextAlign.center),
+                              _buildPdfTableCell(
+                                  penerima.statusPenerimaan ?? '-', ttf,
+                                  align: pw.TextAlign.center),
+                            ],
+                          );
+                        }).toList(),
+                      ],
+                    ),
+                  ],
+                  ttfBold,
+                  PdfColors.blue900,
+                ),
+              ],
+
+              // Dokumentasi & Berita Acara
+              if (laporan.dokumentasiUrl != null ||
+                  laporan.beritaAcaraUrl != null ||
+                  dokumentasiImage != null) ...[
+                pw.SizedBox(height: 15),
+                _buildPdfSection(
+                  'DOKUMENTASI & BERITA ACARA',
+                  [
+                    // // Tampilkan preview gambar dokumentasi jika berhasil diambil
+                    // if (dokumentasiImage != null) ...[
+                    //   pw.Text('Preview Dokumentasi:',
+                    //       style: pw.TextStyle(
+                    //           font: ttfBold, color: PdfColors.blue800)),
+                    //   pw.SizedBox(height: 5),
+                    //   pw.Center(
+                    //     child: pw.Container(
+                    //       decoration: pw.BoxDecoration(
+                    //         border: pw.Border.all(color: PdfColors.grey300),
+                    //       ),
+                    //       child: pw.Image(dokumentasiImage, height: 200),
+                    //     ),
+                    //   ),
+                    //   pw.SizedBox(height: 10),
+                    // ],
+
+                    if (laporan.dokumentasiUrl != null) ...[
+                      if (dokumentasiImage == null) ...[
+                        pw.Text('Dokumentasi:',
+                            style: pw.TextStyle(
+                                font: ttfBold, color: PdfColors.blue800)),
+                        pw.SizedBox(height: 3),
+                      ],
+                      pw.Text(
+                          'Dokumentasi dapat diakses melalui tautan berikut:',
+                          style: pw.TextStyle(font: ttf)),
+                      pw.SizedBox(height: 3),
+                      pw.Text(laporan.dokumentasiUrl!,
+                          style: pw.TextStyle(
+                            font: ttf,
+                            color: PdfColors.blue,
+                            decoration: pw.TextDecoration.underline,
+                          )),
+                      if (laporan.beritaAcaraUrl != null)
+                        pw.SizedBox(height: 10),
+                    ],
+
+                    if (laporan.beritaAcaraUrl != null) ...[
+                      pw.Text('Berita Acara:',
+                          style: pw.TextStyle(
+                              font: ttfBold, color: PdfColors.blue800)),
+                      pw.SizedBox(height: 3),
+                      pw.Text(
+                          'Berita acara dapat diakses melalui tautan berikut:',
+                          style: pw.TextStyle(font: ttf)),
+                      pw.SizedBox(height: 3),
+                      pw.Text(laporan.beritaAcaraUrl!,
+                          style: pw.TextStyle(
+                            font: ttf,
+                            color: PdfColors.blue,
+                            decoration: pw.TextDecoration.underline,
+                          )),
+                    ],
+                  ],
+                  ttfBold,
+                  PdfColors.blue900,
+                ),
+              ],
+
+              // Tanda Tangan
+              pw.SizedBox(height: 30),
+              pw.Row(
+                mainAxisAlignment: pw.MainAxisAlignment.end,
+                children: [
+                  pw.Column(
+                    crossAxisAlignment: pw.CrossAxisAlignment.center,
+                    children: [
+                      pw.Text(
+                        'Penanggung Jawab,',
+                        style: pw.TextStyle(font: ttf),
+                      ),
+                      pw.SizedBox(height: 50), // Ruang untuk tanda tangan
+                      pw.Container(
+                        width: 150,
+                        decoration: pw.BoxDecoration(
+                            border: pw.Border(
+                                top: pw.BorderSide(color: PdfColors.black))),
+                        padding: const pw.EdgeInsets.only(top: 5),
+                        child: pw.Text(
+                          // Sesuaikan dengan properti yang ada di model user
+                          user?.email ?? 'Admin Sistem',
+                          style: pw.TextStyle(font: ttfBold),
+                          textAlign: pw.TextAlign.center,
+                        ),
+                      ),
+                    ],
+                  ),
+                ],
+              ),
+            ];
+          },
+        ),
+      );
+
+      // Simpan dan buka PDF
+      final output = await getTemporaryDirectory();
+      final file =
+          File('${output.path}/laporan_penyaluran_${penyaluran.id}.pdf');
+      await file.writeAsBytes(await pdf.save());
+      await OpenFile.open(file.path);
+
+      Get.snackbar(
+        'Sukses',
+        'Laporan berhasil diekspor ke PDF',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.green,
+        colorText: Colors.white,
+      );
+    } catch (e) {
+      print('Error exporting to PDF: $e');
+      Get.snackbar(
+        'Error',
+        'Gagal mengekspor laporan ke PDF',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+      );
+    } finally {
+      isExporting.value = false;
+    }
+  }
+
+  // Helper untuk membuat section pada PDF
+  pw.Widget _buildPdfSection(String title, List<pw.Widget> content,
+      pw.Font titleFont, PdfColor titleColor) {
+    return pw.Container(
+      decoration: pw.BoxDecoration(
+        border: pw.Border.all(color: PdfColors.grey300),
+        borderRadius: pw.BorderRadius.circular(5),
+      ),
+      child: pw.Column(
+        crossAxisAlignment: pw.CrossAxisAlignment.start,
+        children: [
+          pw.Container(
+            padding: const pw.EdgeInsets.symmetric(horizontal: 10, vertical: 8),
+            decoration: pw.BoxDecoration(
+              color: PdfColors.blue50,
+              border:
+                  pw.Border(bottom: pw.BorderSide(color: PdfColors.grey300)),
+            ),
+            child: pw.Text(
+              title,
+              style: pw.TextStyle(
+                  font: titleFont, fontSize: 14, color: titleColor),
+            ),
+          ),
+          pw.Container(
+            padding: const pw.EdgeInsets.all(10),
+            child: pw.Column(
+              crossAxisAlignment: pw.CrossAxisAlignment.start,
+              children: content,
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  // Helper untuk membuat baris teks di PDF
+  pw.Widget _buildPdfRow(
+      String label, String value, pw.Font font, pw.Font boldFont) {
+    return pw.Padding(
+      padding: const pw.EdgeInsets.symmetric(vertical: 3),
+      child: pw.Row(
+        crossAxisAlignment: pw.CrossAxisAlignment.start,
+        children: [
+          pw.SizedBox(
+            width: 120,
+            child: pw.Text(label,
+                style: pw.TextStyle(font: boldFont, color: PdfColors.blue800)),
+          ),
+          pw.SizedBox(width: 10),
+          pw.Text(':', style: pw.TextStyle(font: boldFont)),
+          pw.SizedBox(width: 10),
+          pw.Expanded(
+            child: pw.Text(value, style: pw.TextStyle(font: font)),
+          ),
+        ],
+      ),
+    );
+  }
+
+  // Helper untuk membuat cell tabel di PDF
+  pw.Widget _buildPdfTableCell(String text, pw.Font font,
+      {bool isHeader = false,
+      pw.TextAlign align = pw.TextAlign.left,
+      PdfColor? color}) {
+    return pw.Padding(
+      padding: const pw.EdgeInsets.all(5),
+      child: pw.Text(
+        text,
+        style: pw.TextStyle(
+          font: font,
+          fontSize: isHeader ? 10 : 9,
+          color: color,
+        ),
+        textAlign: align,
+      ),
+    );
+  }
+}
diff --git a/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_create_view.dart b/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_create_view.dart
new file mode 100644
index 0000000..0074a33
--- /dev/null
+++ b/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_create_view.dart
@@ -0,0 +1,623 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/controllers/laporan_penyaluran_controller.dart';
+import 'package:penyaluran_app/app/theme/app_theme.dart';
+import 'package:penyaluran_app/app/utils/date_time_helper.dart';
+import 'package:penyaluran_app/app/widgets/custom_app_bar.dart';
+import 'package:penyaluran_app/app/widgets/section_header.dart';
+import 'dart:io';
+import 'package:image_picker/image_picker.dart';
+import 'package:file_picker/file_picker.dart';
+
+class LaporanPenyaluranCreateView extends GetView<LaporanPenyaluranController> {
+  const LaporanPenyaluranCreateView({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    final penyaluranId = Get.arguments as String;
+
+    // Dapatkan info penyaluran
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      controller.fetchPenyaluranDetail(penyaluranId);
+      controller.resetForm(); // Reset form setiap kali halaman dibuka
+    });
+
+    return Scaffold(
+      appBar: CustomAppBar(
+        title: 'Buat Laporan Penyaluran',
+        // subtitle: 'Isi form untuk membuat laporan penyaluran',
+        showBackButton: true,
+      ),
+      body: Obx(() {
+        if (controller.isLoading.value) {
+          return const Center(child: CircularProgressIndicator());
+        }
+
+        return SingleChildScrollView(
+          padding: const EdgeInsets.all(16),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              // Informasi penyaluran
+              if (controller.selectedPenyaluran.value != null) ...[
+                Card(
+                  margin: EdgeInsets.zero,
+                  elevation: 2,
+                  shape: RoundedRectangleBorder(
+                    borderRadius: BorderRadius.circular(12),
+                  ),
+                  child: Padding(
+                    padding: const EdgeInsets.all(16),
+                    child: Column(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        const SectionHeader(
+                          title: 'Informasi Penyaluran',
+                          // subtitle: 'Penyaluran yang akan dibuatkan laporan',
+                        ),
+                        const SizedBox(height: 16),
+                        _buildInfoItem(
+                          'Nama Penyaluran',
+                          controller.selectedPenyaluran.value!.nama ?? '-',
+                        ),
+                        _buildInfoItem(
+                          'Tanggal Penyaluran',
+                          controller.selectedPenyaluran.value!
+                                      .tanggalPenyaluran !=
+                                  null
+                              ? DateTimeHelper.formatDateTime(controller
+                                  .selectedPenyaluran.value!.tanggalPenyaluran!)
+                              : '-',
+                        ),
+                        _buildInfoItem(
+                          'Tanggal Selesai',
+                          controller.selectedPenyaluran.value!.tanggalSelesai !=
+                                  null
+                              ? DateTimeHelper.formatDateTime(controller
+                                  .selectedPenyaluran.value!.tanggalSelesai!)
+                              : '-',
+                        ),
+                        _buildInfoItem(
+                          'Jumlah Penerima',
+                          '${controller.selectedPenyaluran.value!.jumlahPenerima ?? 0} orang',
+                        ),
+                      ],
+                    ),
+                  ),
+                ),
+                const SizedBox(height: 24),
+              ],
+
+              // Form laporan
+              Card(
+                margin: EdgeInsets.zero,
+                elevation: 2,
+                shape: RoundedRectangleBorder(
+                  borderRadius: BorderRadius.circular(12),
+                ),
+                child: Padding(
+                  padding: const EdgeInsets.all(16),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      const SectionHeader(
+                        title: 'Form Laporan',
+                      ),
+                      const SizedBox(height: 16),
+
+                      // Judul laporan
+                      _buildTextField(
+                        controller: controller.judulController,
+                        label: 'Judul Laporan',
+                        hint: 'Masukkan judul laporan',
+                        required: true,
+                      ),
+                    ],
+                  ),
+                ),
+              ),
+
+              const SizedBox(height: 24),
+
+              // Dokumentasi dan Berita Acara
+              Card(
+                margin: EdgeInsets.zero,
+                elevation: 2,
+                shape: RoundedRectangleBorder(
+                  borderRadius: BorderRadius.circular(12),
+                ),
+                child: Padding(
+                  padding: const EdgeInsets.all(16),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      const SectionHeader(
+                        title: 'Dokumentasi & Berita Acara',
+                      ),
+                      const SizedBox(height: 16),
+
+                      // Upload Dokumentasi
+                      Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        children: [
+                          RichText(
+                            text: TextSpan(
+                              text: 'Dokumentasi',
+                              style: TextStyle(
+                                fontSize: 14,
+                                fontWeight: FontWeight.w500,
+                                color: AppTheme.primaryColor,
+                              ),
+                            ),
+                          ),
+                          const SizedBox(height: 8),
+                          Obx(
+                            () => controller.dokumentasiPath.isNotEmpty
+                                ? Container(
+                                    width: double.infinity,
+                                    padding: const EdgeInsets.all(12),
+                                    decoration: BoxDecoration(
+                                      color: Colors.grey.shade100,
+                                      borderRadius: BorderRadius.circular(10),
+                                      border: Border.all(
+                                          color: Colors.grey.shade300),
+                                    ),
+                                    child: Column(
+                                      crossAxisAlignment:
+                                          CrossAxisAlignment.start,
+                                      children: [
+                                        ClipRRect(
+                                          borderRadius:
+                                              BorderRadius.circular(8),
+                                          child: Image.file(
+                                            File(controller
+                                                .dokumentasiPath.value),
+                                            width: 200,
+                                            height: 120,
+                                            fit: BoxFit.cover,
+                                            errorBuilder:
+                                                (context, error, stackTrace) =>
+                                                    Container(
+                                              width: 200,
+                                              height: 120,
+                                              color: Colors.grey.shade200,
+                                              child: const Center(
+                                                child: Text(
+                                                    'Pratinjau tidak tersedia'),
+                                              ),
+                                            ),
+                                          ),
+                                        ),
+                                        const SizedBox(height: 8),
+                                        Row(
+                                          mainAxisAlignment:
+                                              MainAxisAlignment.end,
+                                          children: [
+                                            TextButton.icon(
+                                              onPressed: () {
+                                                controller
+                                                    .dokumentasiPath.value = '';
+                                              },
+                                              icon: Icon(Icons.delete,
+                                                  color: AppTheme.errorColor),
+                                              label: Text('Hapus',
+                                                  style: TextStyle(
+                                                      color:
+                                                          AppTheme.errorColor)),
+                                            ),
+                                          ],
+                                        ),
+                                      ],
+                                    ),
+                                  )
+                                : OutlinedButton.icon(
+                                    onPressed: () =>
+                                        _pickDocumentationImage(context),
+                                    icon: const Icon(Icons.upload_file),
+                                    label:
+                                        const Text('Upload Foto Dokumentasi'),
+                                    style: OutlinedButton.styleFrom(
+                                      padding: const EdgeInsets.symmetric(
+                                        vertical: 12,
+                                        horizontal: 16,
+                                      ),
+                                      side: BorderSide(
+                                          color: AppTheme.primaryColor),
+                                    ),
+                                  ),
+                          ),
+                          const SizedBox(height: 4),
+                          Text(
+                            'Format gambar: JPG, PNG, JPEG (maks. 5MB)',
+                            style: TextStyle(
+                              fontSize: 12,
+                              color: Colors.grey[600],
+                              fontStyle: FontStyle.italic,
+                            ),
+                          ),
+                        ],
+                      ),
+
+                      const SizedBox(height: 20),
+
+                      // Upload Berita Acara
+                      Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        children: [
+                          RichText(
+                            text: TextSpan(
+                              text: 'Berita Acara',
+                              style: TextStyle(
+                                fontSize: 14,
+                                fontWeight: FontWeight.w500,
+                                color: AppTheme.primaryColor,
+                              ),
+                            ),
+                          ),
+                          const SizedBox(height: 8),
+                          Obx(
+                            () => controller.beritaAcaraPath.isNotEmpty
+                                ? Container(
+                                    width: double.infinity,
+                                    padding: const EdgeInsets.all(12),
+                                    decoration: BoxDecoration(
+                                      color: Colors.grey.shade100,
+                                      borderRadius: BorderRadius.circular(10),
+                                      border: Border.all(
+                                          color: Colors.grey.shade300),
+                                    ),
+                                    child: Row(
+                                      children: [
+                                        Container(
+                                          padding: const EdgeInsets.all(8),
+                                          decoration: BoxDecoration(
+                                            color: AppTheme.primaryColor
+                                                .withOpacity(0.1),
+                                            borderRadius:
+                                                BorderRadius.circular(8),
+                                          ),
+                                          child: Icon(
+                                            Icons.description,
+                                            color: AppTheme.primaryColor,
+                                          ),
+                                        ),
+                                        const SizedBox(width: 12),
+                                        Expanded(
+                                          child: Column(
+                                            crossAxisAlignment:
+                                                CrossAxisAlignment.start,
+                                            children: [
+                                              Text(
+                                                'Dokumen Berita Acara',
+                                                style: TextStyle(
+                                                  fontWeight: FontWeight.bold,
+                                                  color: AppTheme.primaryColor,
+                                                ),
+                                              ),
+                                              const SizedBox(height: 4),
+                                              Text(
+                                                controller.beritaAcaraPath.value
+                                                    .split('/')
+                                                    .last,
+                                                style: const TextStyle(
+                                                    fontSize: 12),
+                                                maxLines: 1,
+                                                overflow: TextOverflow.ellipsis,
+                                              ),
+                                            ],
+                                          ),
+                                        ),
+                                        IconButton(
+                                          onPressed: () {
+                                            controller.beritaAcaraPath.value =
+                                                '';
+                                          },
+                                          icon: Icon(Icons.delete,
+                                              color: AppTheme.errorColor),
+                                        ),
+                                      ],
+                                    ),
+                                  )
+                                : OutlinedButton.icon(
+                                    onPressed: () =>
+                                        _pickBeritaAcaraFile(context),
+                                    icon: const Icon(Icons.file_present),
+                                    label: const Text(
+                                        'Upload Dokumen Berita Acara'),
+                                    style: OutlinedButton.styleFrom(
+                                      padding: const EdgeInsets.symmetric(
+                                        vertical: 12,
+                                        horizontal: 16,
+                                      ),
+                                      side: BorderSide(
+                                          color: AppTheme.primaryColor),
+                                    ),
+                                  ),
+                          ),
+                          const SizedBox(height: 4),
+                          Text(
+                            'Format file: PDF, DOC, DOCX (maks. 10MB)',
+                            style: TextStyle(
+                              fontSize: 12,
+                              color: Colors.grey[600],
+                              fontStyle: FontStyle.italic,
+                            ),
+                          ),
+                        ],
+                      ),
+                    ],
+                  ),
+                ),
+              ),
+
+              const SizedBox(height: 48),
+
+              // Tombol simpan
+              Obx(() => SizedBox(
+                    width: double.infinity,
+                    child: ElevatedButton(
+                      onPressed: controller.isSaving.value
+                          ? null
+                          : () {
+                              if (controller.judulController.text.isEmpty) {
+                                Get.snackbar(
+                                  'Perhatian',
+                                  'Judul laporan wajib diisi',
+                                  snackPosition: SnackPosition.BOTTOM,
+                                  backgroundColor: AppTheme.warningColor,
+                                  colorText: Colors.white,
+                                );
+                                return;
+                              }
+                              controller.saveLaporan(penyaluranId);
+                            },
+                      style: ElevatedButton.styleFrom(
+                        backgroundColor: AppTheme.primaryColor,
+                        foregroundColor: Colors.white,
+                        padding: const EdgeInsets.symmetric(vertical: 16),
+                        shape: RoundedRectangleBorder(
+                          borderRadius: BorderRadius.circular(12),
+                        ),
+                      ),
+                      child: controller.isSaving.value
+                          ? const SizedBox(
+                              width: 24,
+                              height: 24,
+                              child: CircularProgressIndicator(
+                                color: Colors.white,
+                                strokeWidth: 3,
+                              ),
+                            )
+                          : const Text(
+                              'Simpan Laporan',
+                              style: TextStyle(
+                                fontSize: 16,
+                                fontWeight: FontWeight.bold,
+                              ),
+                            ),
+                    ),
+                  )),
+
+              const SizedBox(height: 32),
+            ],
+          ),
+        );
+      }),
+    );
+  }
+
+  // Metode untuk memilih gambar dokumentasi
+  void _pickDocumentationImage(BuildContext context) {
+    showModalBottomSheet(
+      context: context,
+      shape: const RoundedRectangleBorder(
+        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
+      ),
+      builder: (context) => Container(
+        padding: const EdgeInsets.all(16),
+        child: Column(
+          mainAxisSize: MainAxisSize.min,
+          children: [
+            const Text(
+              'Pilih Sumber Gambar',
+              style: TextStyle(
+                fontSize: 16,
+                fontWeight: FontWeight.bold,
+              ),
+            ),
+            const SizedBox(height: 20),
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+              children: [
+                _buildImageSourceOption(
+                  context,
+                  Icons.camera_alt,
+                  'Kamera',
+                  ImageSource.camera,
+                  Colors.blue,
+                ),
+                _buildImageSourceOption(
+                  context,
+                  Icons.photo_library,
+                  'Galeri',
+                  ImageSource.gallery,
+                  AppTheme.primaryColor,
+                ),
+              ],
+            ),
+            const SizedBox(height: 16),
+          ],
+        ),
+      ),
+    );
+  }
+
+  // Widget untuk opsi sumber gambar
+  Widget _buildImageSourceOption(
+    BuildContext context,
+    IconData icon,
+    String label,
+    ImageSource source,
+    Color color,
+  ) {
+    return InkWell(
+      onTap: () async {
+        Navigator.pop(context);
+        final ImagePicker picker = ImagePicker();
+        try {
+          final XFile? image = await picker.pickImage(
+            source: source,
+            imageQuality: 80,
+          );
+          if (image != null) {
+            controller.dokumentasiPath.value = image.path;
+          }
+        } catch (e) {
+          Get.snackbar(
+            'Error',
+            'Gagal memilih gambar: $e',
+            snackPosition: SnackPosition.BOTTOM,
+            backgroundColor: AppTheme.errorColor,
+            colorText: Colors.white,
+          );
+        }
+      },
+      borderRadius: BorderRadius.circular(12),
+      child: Container(
+        padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 32),
+        decoration: BoxDecoration(
+          color: color.withOpacity(0.1),
+          borderRadius: BorderRadius.circular(12),
+          border: Border.all(color: color.withOpacity(0.3)),
+        ),
+        child: Column(
+          children: [
+            Icon(icon, size: 48, color: color),
+            const SizedBox(height: 8),
+            Text(
+              label,
+              style: TextStyle(
+                color: color,
+                fontWeight: FontWeight.bold,
+              ),
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+
+  // Widget untuk memilih file berita acara
+  Future<void> _pickBeritaAcaraFile(BuildContext context) async {
+    try {
+      final result = await FilePicker.platform.pickFiles(
+        type: FileType.custom,
+        allowedExtensions: ['pdf', 'doc', 'docx'],
+      );
+
+      if (result != null) {
+        controller.beritaAcaraPath.value = result.files.single.path!;
+      }
+    } catch (e) {
+      Get.snackbar(
+        'Error',
+        'Gagal memilih file: $e',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: AppTheme.errorColor,
+        colorText: Colors.white,
+      );
+    }
+  }
+
+  // Widget untuk item informasi
+  Widget _buildInfoItem(String label, String value) {
+    return Padding(
+      padding: const EdgeInsets.only(bottom: 12),
+      child: Row(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          SizedBox(
+            width: 150,
+            child: Text(
+              label,
+              style: TextStyle(
+                fontSize: 14,
+                color: AppTheme.primaryColor,
+              ),
+            ),
+          ),
+          Expanded(
+            child: Text(
+              value,
+              style: const TextStyle(
+                fontSize: 14,
+                fontWeight: FontWeight.bold,
+              ),
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  // Widget untuk input teks
+  Widget _buildTextField({
+    required TextEditingController controller,
+    required String label,
+    required String hint,
+    bool required = false,
+    int maxLines = 1,
+    bool isReadOnly = false,
+  }) {
+    return Padding(
+      padding: const EdgeInsets.only(bottom: 20),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          RichText(
+            text: TextSpan(
+              text: label,
+              style: TextStyle(
+                fontSize: 14,
+                fontWeight: FontWeight.w500,
+                color: AppTheme.primaryColor,
+              ),
+              children: required
+                  ? [
+                      TextSpan(
+                        text: ' *',
+                        style: TextStyle(
+                          color: AppTheme.errorColor,
+                          fontWeight: FontWeight.bold,
+                        ),
+                      ),
+                    ]
+                  : null,
+            ),
+          ),
+          const SizedBox(height: 8),
+          TextField(
+            controller: controller,
+            maxLines: maxLines,
+            readOnly: isReadOnly,
+            decoration: InputDecoration(
+              hintText: hint,
+              hintStyle: TextStyle(color: Colors.grey[400]),
+              filled: true,
+              fillColor: Colors.grey[50],
+              focusedBorder: OutlineInputBorder(
+                borderRadius: BorderRadius.circular(10),
+                borderSide: BorderSide(color: AppTheme.primaryColor, width: 2),
+              ),
+              enabledBorder: OutlineInputBorder(
+                borderRadius: BorderRadius.circular(10),
+                borderSide: BorderSide(color: Colors.grey[300]!),
+              ),
+              contentPadding: const EdgeInsets.all(16),
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_detail_view.dart b/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_detail_view.dart
new file mode 100644
index 0000000..fdfbe7e
--- /dev/null
+++ b/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_detail_view.dart
@@ -0,0 +1,1072 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/controllers/laporan_penyaluran_controller.dart';
+import 'package:penyaluran_app/app/theme/app_theme.dart';
+import 'package:penyaluran_app/app/widgets/custom_app_bar.dart';
+import 'package:penyaluran_app/app/widgets/section_header.dart';
+import 'package:penyaluran_app/app/widgets/status_badge.dart';
+import 'package:intl/intl.dart';
+import 'package:penyaluran_app/app/data/models/penerima_penyaluran_model.dart';
+import 'package:url_launcher/url_launcher.dart';
+
+class LaporanPenyaluranDetailView extends GetView<LaporanPenyaluranController> {
+  const LaporanPenyaluranDetailView({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    final laporanId = Get.arguments as String;
+
+    // Ambil data detail laporan
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      controller.fetchLaporanDetail(laporanId);
+    });
+
+    return Scaffold(
+      appBar: CustomAppBar(
+        title: 'Detail Laporan',
+        // subtitle: 'Informasi lengkap tentang laporan penyaluran',
+        showBackButton: true,
+        actions: [
+          Obx(() {
+            if (controller.isLoading.value) {
+              return const SizedBox.shrink();
+            }
+            if (controller.selectedLaporan.value == null) {
+              return const SizedBox.shrink();
+            }
+            return PopupMenuButton(
+              icon: const Icon(Icons.more_vert),
+              itemBuilder: (context) => [
+                if (controller.selectedLaporan.value!.status != 'FINAL')
+                  PopupMenuItem(
+                    value: 'finalize',
+                    child: Row(
+                      children: const [
+                        Icon(Icons.check_circle, color: Colors.green),
+                        SizedBox(width: 8),
+                        Text('Finalisasi Laporan'),
+                      ],
+                    ),
+                  ),
+                PopupMenuItem(
+                  value: 'edit',
+                  child: Row(
+                    children: const [
+                      Icon(Icons.edit, color: Colors.orange),
+                      SizedBox(width: 8),
+                      Text('Edit Laporan'),
+                    ],
+                  ),
+                ),
+                PopupMenuItem(
+                  value: 'export',
+                  child: Obx(() => Row(
+                        children: [
+                          controller.isExporting.value
+                              ? SizedBox(
+                                  width: 24,
+                                  height: 24,
+                                  child: CircularProgressIndicator(
+                                    strokeWidth: 2,
+                                    color: Colors.blue,
+                                  ),
+                                )
+                              : const Icon(Icons.download, color: Colors.blue),
+                          const SizedBox(width: 8),
+                          Text(controller.isExporting.value
+                              ? 'Mengekspor...'
+                              : 'Export ke PDF'),
+                        ],
+                      )),
+                ),
+                PopupMenuItem(
+                  value: 'delete',
+                  child: Row(
+                    children: const [
+                      Icon(Icons.delete, color: Colors.red),
+                      SizedBox(width: 8),
+                      Text('Hapus Laporan'),
+                    ],
+                  ),
+                ),
+              ],
+              onSelected: (value) {
+                if (value == 'finalize') {
+                  _showFinalizeConfirmation(context, laporanId);
+                } else if (value == 'edit') {
+                  Get.toNamed('/laporan-penyaluran/edit', arguments: laporanId);
+                } else if (value == 'export') {
+                  if (!controller.isExporting.value &&
+                      controller.selectedLaporan.value != null &&
+                      controller.selectedPenyaluran.value != null) {
+                    controller.exportToPdf(controller.selectedLaporan.value!,
+                        controller.selectedPenyaluran.value!);
+                  }
+                } else if (value == 'delete') {
+                  _showDeleteConfirmation(context, laporanId);
+                }
+              },
+            );
+          }),
+        ],
+      ),
+      body: Obx(() {
+        if (controller.isLoading.value) {
+          return const Center(child: CircularProgressIndicator());
+        }
+
+        if (controller.selectedLaporan.value == null) {
+          return const Center(
+            child: Text('Laporan tidak ditemukan'),
+          );
+        }
+
+        final laporan = controller.selectedLaporan.value!;
+        final penyaluran = controller.selectedPenyaluran.value;
+
+        return SingleChildScrollView(
+          padding: const EdgeInsets.all(16),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              // Status dan tanggal
+              _buildStatusHeader(
+                  laporan.status ?? 'DRAFT', laporan.tanggalLaporan),
+
+              const SizedBox(height: 16),
+
+              // Informasi laporan
+              Card(
+                margin: EdgeInsets.zero,
+                elevation: 2,
+                shape: RoundedRectangleBorder(
+                  borderRadius: BorderRadius.circular(12),
+                ),
+                child: Padding(
+                  padding: const EdgeInsets.all(16),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      const SectionHeader(
+                        title: 'Informasi Laporan',
+                      ),
+                      const SizedBox(height: 16),
+                      _buildInfoRow(
+                        'Judul Laporan',
+                        laporan.judul,
+                      ),
+                    ],
+                  ),
+                ),
+              ),
+
+              const SizedBox(height: 24),
+
+              // Informasi penyaluran
+              if (penyaluran != null)
+                Card(
+                  margin: EdgeInsets.zero,
+                  elevation: 2,
+                  shape: RoundedRectangleBorder(
+                    borderRadius: BorderRadius.circular(12),
+                  ),
+                  child: Padding(
+                    padding: const EdgeInsets.all(16),
+                    child: Column(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        const SectionHeader(
+                          title: 'Informasi Penyaluran',
+                          // subtitle: 'Detail informasi penyaluran terkait',
+                        ),
+                        const SizedBox(height: 16),
+                        _buildInfoRow(
+                            'Nama Penyaluran', penyaluran.nama ?? '-'),
+                        _buildInfoRow(
+                          'Tanggal Penyaluran',
+                          penyaluran.tanggalPenyaluran != null
+                              ? DateFormat('dd/MM/yyyy')
+                                  .format(penyaluran.tanggalPenyaluran!)
+                              : '-',
+                        ),
+                        _buildInfoRow(
+                          'Tanggal Selesai',
+                          penyaluran.tanggalSelesai != null
+                              ? DateFormat('dd/MM/yyyy')
+                                  .format(penyaluran.tanggalSelesai!)
+                              : '-',
+                        ),
+                        _buildInfoRow('Jumlah Penerima',
+                            '${penyaluran.jumlahPenerima ?? 0} orang'),
+                        _buildInfoRow(
+                            'Status Penyaluran', penyaluran.status ?? '-'),
+                        if (penyaluran.deskripsi != null &&
+                            penyaluran.deskripsi!.isNotEmpty) ...[
+                          const SizedBox(height: 8),
+                          const Text(
+                            'Deskripsi Penyaluran:',
+                            style: TextStyle(
+                              fontSize: 14,
+                              fontWeight: FontWeight.bold,
+                              color: Colors.grey,
+                            ),
+                          ),
+                          const SizedBox(height: 4),
+                          Text(
+                            penyaluran.deskripsi!,
+                            style: const TextStyle(fontSize: 14),
+                          ),
+                        ],
+                      ],
+                    ),
+                  ),
+                ),
+
+              // Informasi Lokasi Penyaluran
+              if (controller.lokasiPenyaluran.isNotEmpty)
+                Column(
+                  children: [
+                    const SizedBox(height: 24),
+                    Card(
+                      margin: EdgeInsets.zero,
+                      elevation: 2,
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(12),
+                      ),
+                      child: Padding(
+                        padding: const EdgeInsets.all(16),
+                        child: Column(
+                          crossAxisAlignment: CrossAxisAlignment.start,
+                          children: [
+                            const SectionHeader(
+                              title: 'Lokasi Penyaluran',
+                            ),
+                            const SizedBox(height: 16),
+                            _buildInfoRow('Nama Lokasi',
+                                controller.lokasiPenyaluran['nama'] ?? '-'),
+                            _buildInfoRow(
+                                'Alamat',
+                                controller.lokasiPenyaluran['alamat_lengkap'] ??
+                                    '-'),
+                            if (controller.desaData.isNotEmpty) ...[
+                              _buildInfoRow('Desa/Kelurahan',
+                                  controller.desaData['nama'] ?? '-'),
+                              _buildInfoRow('Kecamatan',
+                                  controller.desaData['kecamatan'] ?? '-'),
+                              _buildInfoRow('Kabupaten/Kota',
+                                  controller.desaData['kabupaten'] ?? '-'),
+                              _buildInfoRow('Provinsi',
+                                  controller.desaData['provinsi'] ?? '-'),
+                            ] else ...[
+                              _buildInfoRow(
+                                  'Kecamatan',
+                                  controller.lokasiPenyaluran['kecamatan'] ??
+                                      '-'),
+                              _buildInfoRow(
+                                  'Kabupaten/Kota',
+                                  controller
+                                          .lokasiPenyaluran['kabupaten_kota'] ??
+                                      '-'),
+                              _buildInfoRow(
+                                  'Provinsi',
+                                  controller.lokasiPenyaluran['provinsi'] ??
+                                      '-'),
+                            ],
+                            if (controller.lokasiPenyaluran['keterangan'] !=
+                                    null &&
+                                controller.lokasiPenyaluran['keterangan']
+                                    .toString()
+                                    .isNotEmpty) ...[
+                              const SizedBox(height: 16),
+                              const Text(
+                                'Keterangan Lokasi:',
+                                style: TextStyle(
+                                  fontSize: 14,
+                                  fontWeight: FontWeight.bold,
+                                  color: Colors.grey,
+                                ),
+                              ),
+                              const SizedBox(height: 4),
+                              Text(
+                                controller.lokasiPenyaluran['keterangan'],
+                                style: const TextStyle(fontSize: 14),
+                              ),
+                            ],
+                          ],
+                        ),
+                      ),
+                    ),
+                  ],
+                ),
+
+              // Informasi Stok Bantuan yang Digunakan
+              if (controller.stokBantuanUsage.isNotEmpty)
+                Column(
+                  children: [
+                    const SizedBox(height: 24),
+                    Card(
+                      margin: EdgeInsets.zero,
+                      elevation: 2,
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(12),
+                      ),
+                      child: Padding(
+                        padding: const EdgeInsets.all(16),
+                        child: Column(
+                          crossAxisAlignment: CrossAxisAlignment.start,
+                          children: [
+                            const SectionHeader(
+                              title: 'Stok Bantuan yang Digunakan',
+                            ),
+                            const SizedBox(height: 16),
+
+                            // Informasi kategori bantuan jika tersedia
+                            if (controller.kategoriBantuan.isNotEmpty) ...[
+                              Container(
+                                padding: const EdgeInsets.all(12),
+                                decoration: BoxDecoration(
+                                  color: Colors.blue.shade50,
+                                  borderRadius: BorderRadius.circular(10),
+                                  border:
+                                      Border.all(color: Colors.blue.shade100),
+                                ),
+                                child: Column(
+                                  crossAxisAlignment: CrossAxisAlignment.start,
+                                  children: [
+                                    Row(
+                                      children: [
+                                        Icon(Icons.category,
+                                            color: Colors.blue.shade700),
+                                        const SizedBox(width: 8),
+                                        Text(
+                                          'Kategori Bantuan: ${controller.kategoriBantuan['nama'] ?? 'Tidak Diketahui'}',
+                                          style: TextStyle(
+                                            fontWeight: FontWeight.bold,
+                                            fontSize: 16,
+                                            color: Colors.blue.shade800,
+                                          ),
+                                        ),
+                                      ],
+                                    ),
+                                    if (controller
+                                            .kategoriBantuan['deskripsi'] !=
+                                        null) ...[
+                                      const SizedBox(height: 8),
+                                      Text(
+                                        controller.kategoriBantuan['deskripsi'],
+                                        style: TextStyle(
+                                          color: Colors.blue.shade700,
+                                          fontSize: 14,
+                                        ),
+                                      ),
+                                    ],
+                                  ],
+                                ),
+                              ),
+                              const SizedBox(height: 16),
+                            ],
+
+                            // Daftar stok bantuan
+                            ListView.builder(
+                              shrinkWrap: true,
+                              physics: const NeverScrollableScrollPhysics(),
+                              itemCount: controller.stokBantuanUsage.length,
+                              itemBuilder: (context, index) {
+                                final stokId = controller.stokBantuanUsage.keys
+                                    .elementAt(index);
+                                final jumlah =
+                                    controller.stokBantuanUsage[stokId];
+
+                                // Find stok bantuan details
+                                final stokBantuan = controller.daftarPenerima
+                                    .firstWhere(
+                                        (p) => p.stokBantuanId == stokId,
+                                        orElse: () => PenerimaPenyaluranModel())
+                                    .stokBantuan;
+
+                                if (stokBantuan == null)
+                                  return const SizedBox.shrink();
+
+                                final kategori =
+                                    stokBantuan['kategori_bantuan'] != null
+                                        ? stokBantuan['kategori_bantuan']
+                                                ['nama'] ??
+                                            '-'
+                                        : '-';
+
+                                final isUang = stokBantuan['is_uang'] == true;
+
+                                return Padding(
+                                  padding: const EdgeInsets.only(bottom: 8),
+                                  child: Card(
+                                    color: isUang
+                                        ? Colors.green.shade50
+                                        : Colors.grey.shade50,
+                                    margin: EdgeInsets.zero,
+                                    child: Padding(
+                                      padding: const EdgeInsets.all(12),
+                                      child: Column(
+                                        crossAxisAlignment:
+                                            CrossAxisAlignment.start,
+                                        children: [
+                                          Row(
+                                            mainAxisAlignment:
+                                                MainAxisAlignment.spaceBetween,
+                                            children: [
+                                              Expanded(
+                                                child: Text(
+                                                  stokBantuan['nama'] ?? '-',
+                                                  style: const TextStyle(
+                                                    fontWeight: FontWeight.bold,
+                                                    fontSize: 15,
+                                                  ),
+                                                ),
+                                              ),
+                                              Container(
+                                                padding:
+                                                    const EdgeInsets.symmetric(
+                                                        horizontal: 8,
+                                                        vertical: 4),
+                                                decoration: BoxDecoration(
+                                                  color: isUang
+                                                      ? Colors.green.shade100
+                                                      : Colors.blue.shade100,
+                                                  borderRadius:
+                                                      BorderRadius.circular(12),
+                                                ),
+                                                child: Text(
+                                                  kategori,
+                                                  style: TextStyle(
+                                                    fontSize: 12,
+                                                    color: isUang
+                                                        ? Colors.green.shade800
+                                                        : Colors.blue.shade800,
+                                                  ),
+                                                ),
+                                              ),
+                                            ],
+                                          ),
+                                          const SizedBox(height: 8),
+                                          Row(
+                                            children: [
+                                              const Text(
+                                                'Jumlah digunakan: ',
+                                                style: TextStyle(fontSize: 14),
+                                              ),
+                                              Text(
+                                                isUang
+                                                    ? 'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(jumlah)}'
+                                                    : '$jumlah ${stokBantuan['satuan'] ?? ''}',
+                                                style: const TextStyle(
+                                                  fontWeight: FontWeight.bold,
+                                                  fontSize: 14,
+                                                ),
+                                              ),
+                                            ],
+                                          ),
+                                          if (stokBantuan['deskripsi'] !=
+                                                  null &&
+                                              stokBantuan['deskripsi']
+                                                  .toString()
+                                                  .isNotEmpty) ...[
+                                            const SizedBox(height: 8),
+                                            Text(
+                                              stokBantuan['deskripsi'],
+                                              style: TextStyle(
+                                                fontSize: 13,
+                                                color: Colors.grey[600],
+                                              ),
+                                            ),
+                                          ],
+                                        ],
+                                      ),
+                                    ),
+                                  ),
+                                );
+                              },
+                            ),
+                          ],
+                        ),
+                      ),
+                    ),
+                  ],
+                ),
+
+              // Daftar Penerima Bantuan
+              if (controller.daftarPenerima.isNotEmpty)
+                Column(
+                  children: [
+                    const SizedBox(height: 24),
+                    Card(
+                      margin: EdgeInsets.zero,
+                      elevation: 2,
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(12),
+                      ),
+                      child: Padding(
+                        padding: const EdgeInsets.all(16),
+                        child: Column(
+                          crossAxisAlignment: CrossAxisAlignment.start,
+                          children: [
+                            const SectionHeader(
+                              title: 'Daftar Penerima Bantuan',
+                            ),
+                            const SizedBox(height: 16),
+                            // Header Tabel
+                            Container(
+                              padding: const EdgeInsets.symmetric(
+                                  vertical: 8, horizontal: 12),
+                              decoration: BoxDecoration(
+                                color: Colors.grey.shade100,
+                                borderRadius: BorderRadius.circular(8),
+                              ),
+                              child: Row(
+                                children: const [
+                                  Expanded(
+                                    flex: 3,
+                                    child: Text(
+                                      'Nama Penerima',
+                                      style: TextStyle(
+                                          fontWeight: FontWeight.bold),
+                                    ),
+                                  ),
+                                  Expanded(
+                                    flex: 3,
+                                    child: Text(
+                                      'Jenis Bantuan',
+                                      style: TextStyle(
+                                          fontWeight: FontWeight.bold),
+                                    ),
+                                  ),
+                                  Expanded(
+                                    flex: 2,
+                                    child: Text(
+                                      'Jumlah',
+                                      style: TextStyle(
+                                          fontWeight: FontWeight.bold),
+                                      textAlign: TextAlign.center,
+                                    ),
+                                  ),
+                                  Expanded(
+                                    flex: 2,
+                                    child: Text(
+                                      'Status',
+                                      style: TextStyle(
+                                          fontWeight: FontWeight.bold),
+                                      textAlign: TextAlign.center,
+                                    ),
+                                  ),
+                                ],
+                              ),
+                            ),
+
+                            // Baris Data Penerima
+                            ListView.builder(
+                              shrinkWrap: true,
+                              physics: const NeverScrollableScrollPhysics(),
+                              itemCount: controller.daftarPenerima.length,
+                              itemBuilder: (context, index) {
+                                final penerima =
+                                    controller.daftarPenerima[index];
+                                final wargaNama = penerima.warga != null
+                                    ? penerima.warga!['nama_lengkap'] ?? '-'
+                                    : '-';
+                                final stokNama = penerima.stokBantuan != null
+                                    ? penerima.stokBantuan!['nama'] ?? '-'
+                                    : '-';
+                                final jumlah = penerima.jumlahBantuan != null
+                                    ? '${penerima.jumlahBantuan} ${penerima.satuan ?? ''}'
+                                    : '-';
+
+                                return Container(
+                                  padding: const EdgeInsets.symmetric(
+                                      vertical: 12, horizontal: 12),
+                                  decoration: BoxDecoration(
+                                    border: Border(
+                                      bottom: BorderSide(
+                                          color: Colors.grey.shade200),
+                                    ),
+                                  ),
+                                  child: Row(
+                                    children: [
+                                      Expanded(
+                                        flex: 3,
+                                        child: Text(wargaNama),
+                                      ),
+                                      Expanded(
+                                        flex: 3,
+                                        child: Text(stokNama),
+                                      ),
+                                      Expanded(
+                                        flex: 2,
+                                        child: Text(
+                                          jumlah,
+                                          textAlign: TextAlign.center,
+                                        ),
+                                      ),
+                                      Expanded(
+                                        flex: 2,
+                                        child: Container(
+                                          padding: const EdgeInsets.symmetric(
+                                              horizontal: 6, vertical: 4),
+                                          decoration: BoxDecoration(
+                                            color: _getStatusColor(
+                                                penerima.statusPenerimaan),
+                                            borderRadius:
+                                                BorderRadius.circular(12),
+                                          ),
+                                          child: Text(
+                                            penerima.statusPenerimaan ?? '-',
+                                            style: const TextStyle(
+                                              fontSize: 10,
+                                              color: Colors.white,
+                                            ),
+                                            textAlign: TextAlign.center,
+                                          ),
+                                        ),
+                                      ),
+                                    ],
+                                  ),
+                                );
+                              },
+                            ),
+                          ],
+                        ),
+                      ),
+                    ),
+                  ],
+                ),
+
+              // Dokumentasi dan Berita Acara
+              if (controller.selectedLaporan.value?.dokumentasiUrl != null ||
+                  controller.selectedLaporan.value?.beritaAcaraUrl != null)
+                Column(
+                  children: [
+                    const SizedBox(height: 24),
+                    Card(
+                      margin: EdgeInsets.zero,
+                      elevation: 2,
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(12),
+                      ),
+                      child: Padding(
+                        padding: const EdgeInsets.all(16),
+                        child: Column(
+                          crossAxisAlignment: CrossAxisAlignment.start,
+                          children: [
+                            const SectionHeader(
+                              title: 'Dokumentasi & Berita Acara',
+                            ),
+                            const SizedBox(height: 16),
+
+                            // Dokumentasi
+                            if (controller
+                                    .selectedLaporan.value?.dokumentasiUrl !=
+                                null) ...[
+                              const Text(
+                                'Dokumentasi:',
+                                style: TextStyle(
+                                  fontSize: 14,
+                                  fontWeight: FontWeight.bold,
+                                  color: Colors.grey,
+                                ),
+                              ),
+                              const SizedBox(height: 8),
+                              ClipRRect(
+                                borderRadius: BorderRadius.circular(10),
+                                child: Image.network(
+                                  controller
+                                      .selectedLaporan.value!.dokumentasiUrl!,
+                                  width: double.infinity,
+                                  height: 200,
+                                  fit: BoxFit.cover,
+                                  errorBuilder: (context, error, stackTrace) =>
+                                      Container(
+                                    width: double.infinity,
+                                    height: 50,
+                                    color: Colors.grey[200],
+                                    child: const Center(
+                                      child: Text('Gagal memuat gambar'),
+                                    ),
+                                  ),
+                                ),
+                              ),
+                              const SizedBox(height: 16),
+                              Center(
+                                child: ElevatedButton.icon(
+                                  onPressed: () async {
+                                    final Uri url = Uri.parse(controller
+                                        .selectedLaporan
+                                        .value!
+                                        .dokumentasiUrl!);
+                                    if (!await launchUrl(url)) {
+                                      throw Exception(
+                                          'Tidak dapat membuka $url');
+                                    }
+                                  },
+                                  icon: const Icon(Icons.image),
+                                  label: const Text('Lihat Dokumentasi'),
+                                  style: ElevatedButton.styleFrom(
+                                    backgroundColor: Colors.blue,
+                                  ),
+                                ),
+                              ),
+                            ],
+
+                            if (controller.selectedLaporan.value
+                                        ?.dokumentasiUrl !=
+                                    null &&
+                                controller.selectedLaporan.value
+                                        ?.beritaAcaraUrl !=
+                                    null)
+                              const SizedBox(height: 16),
+
+                            // Berita Acara
+                            if (controller
+                                    .selectedLaporan.value?.beritaAcaraUrl !=
+                                null) ...[
+                              const Text(
+                                'Berita Acara:',
+                                style: TextStyle(
+                                  fontSize: 14,
+                                  fontWeight: FontWeight.bold,
+                                  color: Colors.grey,
+                                ),
+                              ),
+                              const SizedBox(height: 8),
+                              ListTile(
+                                leading: const Icon(
+                                  Icons.description,
+                                  color: Colors.blue,
+                                  size: 40,
+                                ),
+                                title: const Text(
+                                  'Dokumen Berita Acara',
+                                  style: TextStyle(fontWeight: FontWeight.bold),
+                                ),
+                                subtitle:
+                                    const Text('Tap untuk membuka dokumen'),
+                                shape: RoundedRectangleBorder(
+                                  borderRadius: BorderRadius.circular(8),
+                                  side: BorderSide(color: Colors.grey.shade300),
+                                ),
+                                onTap: () async {
+                                  final Uri url = Uri.parse(controller
+                                      .selectedLaporan.value!.beritaAcaraUrl!);
+                                  if (!await launchUrl(url)) {
+                                    throw Exception('Tidak dapat membuka $url');
+                                  }
+                                },
+                              ),
+                            ],
+                          ],
+                        ),
+                      ),
+                    ),
+                  ],
+                ),
+              const SizedBox(height: 24),
+
+              // Tombol aksi
+              Row(
+                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                children: [
+                  if (laporan.status != 'FINAL')
+                    Expanded(
+                      child: ElevatedButton.icon(
+                        onPressed: () =>
+                            _showFinalizeConfirmation(context, laporanId),
+                        icon: const Icon(Icons.check_circle),
+                        label: const Text('Finalisasi'),
+                        style: ElevatedButton.styleFrom(
+                          backgroundColor: Colors.green,
+                          padding: const EdgeInsets.symmetric(vertical: 12),
+                        ),
+                      ),
+                    ),
+                  if (laporan.status != 'FINAL') const SizedBox(width: 12),
+                  Expanded(
+                    child: Obx(() => ElevatedButton.icon(
+                          onPressed: controller.isExporting.value
+                              ? null
+                              : () {
+                                  if (controller.selectedLaporan.value !=
+                                          null &&
+                                      controller.selectedPenyaluran.value !=
+                                          null) {
+                                    controller.exportToPdf(
+                                        controller.selectedLaporan.value!,
+                                        controller.selectedPenyaluran.value!);
+                                  }
+                                },
+                          icon: controller.isExporting.value
+                              ? SizedBox(
+                                  width: 24,
+                                  height: 24,
+                                  child: CircularProgressIndicator(
+                                    strokeWidth: 2,
+                                    valueColor: AlwaysStoppedAnimation<Color>(
+                                        Colors.white),
+                                  ),
+                                )
+                              : const Icon(Icons.download),
+                          label: Text(controller.isExporting.value
+                              ? 'Mengekspor...'
+                              : 'Export PDF'),
+                          style: ElevatedButton.styleFrom(
+                            backgroundColor: Colors.blue,
+                            padding: const EdgeInsets.symmetric(vertical: 12),
+                            disabledBackgroundColor:
+                                Colors.blue.withOpacity(0.7),
+                          ),
+                        )),
+                  ),
+                ],
+              ),
+            ],
+          ),
+        );
+      }),
+    );
+  }
+
+  // Membangun header status
+  Widget _buildStatusHeader(String status, DateTime? tanggalLaporan) {
+    return Container(
+      padding: const EdgeInsets.all(16),
+      decoration: BoxDecoration(
+        color: AppTheme.primaryColor.withOpacity(0.1),
+        borderRadius: BorderRadius.circular(12),
+      ),
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        children: [
+          Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Text(
+                'Status Laporan',
+                style: TextStyle(
+                  fontSize: 14,
+                  color: AppTheme.primaryColor,
+                ),
+              ),
+              const SizedBox(height: 6),
+              StatusBadge(status: status),
+            ],
+          ),
+          Column(
+            crossAxisAlignment: CrossAxisAlignment.end,
+            children: [
+              Text(
+                'Tanggal Laporan',
+                style: TextStyle(
+                  fontSize: 14,
+                  color: AppTheme.primaryColor,
+                ),
+              ),
+              const SizedBox(height: 6),
+              Text(
+                tanggalLaporan != null
+                    ? DateFormat('dd/MM/yyyy').format(tanggalLaporan)
+                    : '-',
+                style: const TextStyle(
+                  fontSize: 14,
+                  fontWeight: FontWeight.bold,
+                ),
+              ),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+
+  // Membangun baris informasi
+  Widget _buildInfoRow(String label, String value) {
+    return Padding(
+      padding: const EdgeInsets.only(bottom: 12),
+      child: Row(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          SizedBox(
+            width: 150,
+            child: Text(
+              label,
+              style: TextStyle(
+                fontSize: 14,
+                color: AppTheme.primaryColor,
+              ),
+            ),
+          ),
+          Expanded(
+            child: Text(
+              value,
+              style: const TextStyle(
+                fontSize: 14,
+                fontWeight: FontWeight.bold,
+              ),
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  // Helper untuk mendapatkan warna status penerimaan
+  Color _getStatusColor(String? status) {
+    if (status == null) return Colors.grey;
+
+    switch (status.toUpperCase()) {
+      case 'DITERIMA':
+        return Colors.green;
+      case 'TERTUNDA':
+        return Colors.orange;
+      case 'DIBATALKAN':
+        return Colors.red;
+      case 'SEDANG DIPROSES':
+        return Colors.blue;
+      default:
+        return Colors.grey;
+    }
+  }
+
+  // Menampilkan dokumen
+  Widget _buildDocumentSection(String judul, String? url, IconData icon) {
+    if (url == null || url.isEmpty) {
+      return const SizedBox.shrink();
+    }
+
+    return InkWell(
+      onTap: () async {
+        final Uri _url = Uri.parse(url);
+        if (await canLaunchUrl(_url)) {
+          await launchUrl(_url, mode: LaunchMode.externalApplication);
+        } else {
+          Get.snackbar(
+            'Error',
+            'Tidak dapat membuka dokumen',
+            snackPosition: SnackPosition.BOTTOM,
+            backgroundColor: AppTheme.errorColor,
+            colorText: Colors.white,
+          );
+        }
+      },
+      child: Container(
+        padding: const EdgeInsets.all(16),
+        margin: const EdgeInsets.only(bottom: 12),
+        decoration: BoxDecoration(
+          color: AppTheme.primaryColor.withOpacity(0.05),
+          borderRadius: BorderRadius.circular(12),
+          border: Border.all(
+            color: AppTheme.primaryColor.withOpacity(0.2),
+          ),
+        ),
+        child: Row(
+          children: [
+            Icon(
+              icon,
+              color: AppTheme.primaryColor,
+              size: 24,
+            ),
+            const SizedBox(width: 16),
+            Expanded(
+              child: Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  Text(
+                    judul,
+                    style: TextStyle(
+                      fontWeight: FontWeight.bold,
+                      color: AppTheme.primaryColor,
+                    ),
+                  ),
+                  const SizedBox(height: 4),
+                  const Text(
+                    'Tap untuk membuka dokumen',
+                    style: TextStyle(fontSize: 12, color: Colors.grey),
+                  ),
+                ],
+              ),
+            ),
+            Icon(
+              Icons.open_in_new,
+              color: AppTheme.primaryColor,
+              size: 20,
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+
+  // Dialog konfirmasi finalisasi laporan
+  void _showFinalizeConfirmation(BuildContext context, String laporanId) {
+    showDialog(
+      context: context,
+      builder: (BuildContext context) {
+        return AlertDialog(
+          title: const Text('Finalisasi Laporan'),
+          content: const Text(
+              'Laporan yang sudah difinalisasi tidak dapat diubah lagi. Lanjutkan?'),
+          actions: <Widget>[
+            TextButton(
+              onPressed: () {
+                Navigator.of(context).pop();
+              },
+              child: Text(
+                'Batal',
+                style: TextStyle(color: AppTheme.primaryColor),
+              ),
+            ),
+            ElevatedButton(
+              style: ElevatedButton.styleFrom(
+                backgroundColor: AppTheme.primaryColor,
+              ),
+              onPressed: () {
+                Navigator.of(context).pop();
+                controller.finalizeLaporan(laporanId);
+              },
+              child: const Text('Finalisasi'),
+            ),
+          ],
+        );
+      },
+    );
+  }
+
+  // Dialog konfirmasi hapus laporan
+  void _showDeleteConfirmation(BuildContext context, String laporanId) {
+    showDialog(
+      context: context,
+      builder: (BuildContext context) {
+        return AlertDialog(
+          title: const Text('Hapus Laporan'),
+          content: const Text(
+              'Laporan yang dihapus tidak dapat dikembalikan. Lanjutkan?'),
+          actions: <Widget>[
+            TextButton(
+              onPressed: () {
+                Navigator.of(context).pop();
+              },
+              child: Text(
+                'Batal',
+                style: TextStyle(color: AppTheme.primaryColor),
+              ),
+            ),
+            ElevatedButton(
+              style: ElevatedButton.styleFrom(
+                backgroundColor: AppTheme.errorColor,
+              ),
+              onPressed: () {
+                Navigator.of(context).pop();
+                controller.deleteLaporan(laporanId);
+              },
+              child: const Text('Hapus'),
+            ),
+          ],
+        );
+      },
+    );
+  }
+}
diff --git a/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_edit_view.dart b/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_edit_view.dart
new file mode 100644
index 0000000..65796bb
--- /dev/null
+++ b/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_edit_view.dart
@@ -0,0 +1,700 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/controllers/laporan_penyaluran_controller.dart';
+import 'package:penyaluran_app/app/widgets/custom_app_bar.dart';
+import 'package:penyaluran_app/app/widgets/section_header.dart';
+import 'dart:io';
+import 'package:image_picker/image_picker.dart';
+import 'package:file_picker/file_picker.dart';
+
+class LaporanPenyaluranEditView extends GetView<LaporanPenyaluranController> {
+  const LaporanPenyaluranEditView({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    final laporanId = Get.arguments as String;
+
+    // Dapatkan data laporan
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      controller.fetchLaporanDetail(laporanId).then((_) {
+        if (controller.selectedLaporan.value != null) {
+          controller.setFormForEdit(controller.selectedLaporan.value!);
+        }
+      });
+    });
+
+    return Scaffold(
+      appBar: CustomAppBar(
+        title: 'Edit Laporan Penyaluran',
+        // subtitle: 'Perbarui informasi laporan penyaluran',
+        showBackButton: true,
+      ),
+      body: Obx(() {
+        if (controller.isLoading.value) {
+          return const Center(child: CircularProgressIndicator());
+        }
+
+        if (controller.selectedLaporan.value == null) {
+          return const Center(
+            child: Text('Laporan tidak ditemukan'),
+          );
+        }
+
+        // Cek status laporan
+        if (controller.selectedLaporan.value!.status == 'FINAL') {
+          return Center(
+            child: Padding(
+              padding: const EdgeInsets.all(24.0),
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  const Icon(
+                    Icons.lock,
+                    size: 64,
+                    color: Colors.orange,
+                  ),
+                  const SizedBox(height: 16),
+                  const Text(
+                    'Laporan Telah Difinalisasi',
+                    style: TextStyle(
+                      fontSize: 18,
+                      fontWeight: FontWeight.bold,
+                    ),
+                  ),
+                  const SizedBox(height: 8),
+                  const Text(
+                    'Laporan yang sudah difinalisasi tidak dapat diedit lagi.',
+                    textAlign: TextAlign.center,
+                    style: TextStyle(
+                      color: Colors.grey,
+                      fontSize: 16,
+                    ),
+                  ),
+                  const SizedBox(height: 24),
+                  ElevatedButton(
+                    onPressed: () => Get.back(),
+                    child: const Text('Kembali ke Detail Laporan'),
+                  ),
+                ],
+              ),
+            ),
+          );
+        }
+
+        return SingleChildScrollView(
+          padding: const EdgeInsets.all(16),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              // Informasi penyaluran
+              if (controller.selectedPenyaluran.value != null) ...[
+                Card(
+                  margin: EdgeInsets.zero,
+                  elevation: 2,
+                  shape: RoundedRectangleBorder(
+                    borderRadius: BorderRadius.circular(12),
+                  ),
+                  child: Padding(
+                    padding: const EdgeInsets.all(16),
+                    child: Column(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        const SectionHeader(
+                          title: 'Informasi Penyaluran',
+                          // subtitle: 'Penyaluran yang terkait dengan laporan',
+                        ),
+                        const SizedBox(height: 16),
+                        _buildInfoItem(
+                          'Nama Penyaluran',
+                          controller.selectedPenyaluran.value!.nama ?? '-',
+                        ),
+                        _buildInfoItem(
+                          'Tanggal Penyaluran',
+                          controller.selectedPenyaluran.value!
+                                      .tanggalPenyaluran !=
+                                  null
+                              ? '${controller.selectedPenyaluran.value!.tanggalPenyaluran!.day}/${controller.selectedPenyaluran.value!.tanggalPenyaluran!.month}/${controller.selectedPenyaluran.value!.tanggalPenyaluran!.year}'
+                              : '-',
+                        ),
+                        _buildInfoItem(
+                          'Tanggal Selesai',
+                          controller.selectedPenyaluran.value!.tanggalSelesai !=
+                                  null
+                              ? '${controller.selectedPenyaluran.value!.tanggalSelesai!.day}/${controller.selectedPenyaluran.value!.tanggalSelesai!.month}/${controller.selectedPenyaluran.value!.tanggalSelesai!.year}'
+                              : '-',
+                        ),
+                        _buildInfoItem(
+                          'Jumlah Penerima',
+                          '${controller.selectedPenyaluran.value!.jumlahPenerima ?? 0} orang',
+                        ),
+                      ],
+                    ),
+                  ),
+                ),
+                const SizedBox(height: 24),
+              ],
+
+              // Form laporan
+              Card(
+                margin: EdgeInsets.zero,
+                elevation: 2,
+                shape: RoundedRectangleBorder(
+                  borderRadius: BorderRadius.circular(12),
+                ),
+                child: Padding(
+                  padding: const EdgeInsets.all(16),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      const SectionHeader(
+                        title: 'Form Laporan',
+                      ),
+                      const SizedBox(height: 16),
+
+                      // Judul laporan
+                      _buildTextField(
+                        controller: controller.judulController,
+                        label: 'Judul Laporan',
+                        hint: 'Masukkan judul laporan',
+                        required: true,
+                      ),
+                    ],
+                  ),
+                ),
+              ),
+
+              const SizedBox(height: 24),
+
+              // Dokumentasi dan Berita Acara
+              Card(
+                margin: EdgeInsets.zero,
+                elevation: 2,
+                shape: RoundedRectangleBorder(
+                  borderRadius: BorderRadius.circular(12),
+                ),
+                child: Padding(
+                  padding: const EdgeInsets.all(16),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      const SectionHeader(
+                        title: 'Dokumentasi & Berita Acara',
+                      ),
+                      const SizedBox(height: 16),
+
+                      // Upload Dokumentasi
+                      Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        children: [
+                          RichText(
+                            text: TextSpan(
+                              text: 'Dokumentasi',
+                              style: TextStyle(
+                                fontSize: 14,
+                                fontWeight: FontWeight.w500,
+                                color: Colors.grey[800],
+                              ),
+                            ),
+                          ),
+                          const SizedBox(height: 8),
+
+                          // Dokumentasi yang sudah ada
+                          if (controller
+                                      .selectedLaporan.value?.dokumentasiUrl !=
+                                  null &&
+                              controller.dokumentasiPath.isEmpty)
+                            Container(
+                              width: double.infinity,
+                              padding: const EdgeInsets.all(12),
+                              decoration: BoxDecoration(
+                                color: Colors.grey.shade100,
+                                borderRadius: BorderRadius.circular(10),
+                                border: Border.all(color: Colors.grey.shade300),
+                              ),
+                              child: Column(
+                                crossAxisAlignment: CrossAxisAlignment.start,
+                                children: [
+                                  ClipRRect(
+                                    borderRadius: BorderRadius.circular(8),
+                                    child: Image.network(
+                                      controller.selectedLaporan.value!
+                                          .dokumentasiUrl!,
+                                      width: 200,
+                                      height: 120,
+                                      fit: BoxFit.cover,
+                                      errorBuilder:
+                                          (context, error, stackTrace) =>
+                                              Container(
+                                        width: 200,
+                                        height: 120,
+                                        color: Colors.grey.shade200,
+                                        child: const Center(
+                                          child:
+                                              Text('Pratinjau tidak tersedia'),
+                                        ),
+                                      ),
+                                    ),
+                                  ),
+                                  const SizedBox(height: 8),
+                                  Row(
+                                    mainAxisAlignment: MainAxisAlignment.end,
+                                    children: [
+                                      TextButton.icon(
+                                        onPressed: () =>
+                                            _pickDocumentationImage(context),
+                                        icon: const Icon(Icons.edit,
+                                            color: Colors.blue),
+                                        label: const Text('Ganti',
+                                            style:
+                                                TextStyle(color: Colors.blue)),
+                                      ),
+                                    ],
+                                  ),
+                                ],
+                              ),
+                            )
+                          // Dokumentasi yang baru dipilih
+                          else if (controller.dokumentasiPath.isNotEmpty)
+                            Container(
+                              width: double.infinity,
+                              padding: const EdgeInsets.all(12),
+                              decoration: BoxDecoration(
+                                color: Colors.grey.shade100,
+                                borderRadius: BorderRadius.circular(10),
+                                border: Border.all(color: Colors.grey.shade300),
+                              ),
+                              child: Column(
+                                crossAxisAlignment: CrossAxisAlignment.start,
+                                children: [
+                                  ClipRRect(
+                                    borderRadius: BorderRadius.circular(8),
+                                    child: Image.file(
+                                      File(controller.dokumentasiPath.value),
+                                      width: 200,
+                                      height: 120,
+                                      fit: BoxFit.cover,
+                                      errorBuilder:
+                                          (context, error, stackTrace) =>
+                                              Container(
+                                        width: 200,
+                                        height: 120,
+                                        color: Colors.grey.shade200,
+                                        child: const Center(
+                                          child:
+                                              Text('Pratinjau tidak tersedia'),
+                                        ),
+                                      ),
+                                    ),
+                                  ),
+                                  const SizedBox(height: 8),
+                                  Row(
+                                    mainAxisAlignment: MainAxisAlignment.end,
+                                    children: [
+                                      TextButton.icon(
+                                        onPressed: () {
+                                          controller.dokumentasiPath.value = '';
+                                        },
+                                        icon: const Icon(Icons.delete,
+                                            color: Colors.red),
+                                        label: const Text('Hapus',
+                                            style:
+                                                TextStyle(color: Colors.red)),
+                                      ),
+                                    ],
+                                  ),
+                                ],
+                              ),
+                            )
+                          // Tidak ada dokumentasi
+                          else
+                            OutlinedButton.icon(
+                              onPressed: () => _pickDocumentationImage(context),
+                              icon: const Icon(Icons.upload_file),
+                              label: const Text('Upload Foto Dokumentasi'),
+                              style: OutlinedButton.styleFrom(
+                                padding: const EdgeInsets.symmetric(
+                                  vertical: 12,
+                                  horizontal: 16,
+                                ),
+                                side: BorderSide(color: Colors.blue.shade300),
+                              ),
+                            ),
+                          const SizedBox(height: 4),
+                          Text(
+                            'Format gambar: JPG, PNG, JPEG (maks. 5MB)',
+                            style: TextStyle(
+                              fontSize: 12,
+                              color: Colors.grey[600],
+                              fontStyle: FontStyle.italic,
+                            ),
+                          ),
+                        ],
+                      ),
+
+                      const SizedBox(height: 20),
+
+                      // Upload Berita Acara
+                      Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        children: [
+                          RichText(
+                            text: TextSpan(
+                              text: 'Berita Acara',
+                              style: TextStyle(
+                                fontSize: 14,
+                                fontWeight: FontWeight.w500,
+                                color: Colors.grey[800],
+                              ),
+                            ),
+                          ),
+                          const SizedBox(height: 8),
+
+                          // Berita acara yang sudah ada
+                          if (controller
+                                      .selectedLaporan.value?.beritaAcaraUrl !=
+                                  null &&
+                              controller.beritaAcaraPath.isEmpty)
+                            Container(
+                              width: double.infinity,
+                              padding: const EdgeInsets.all(12),
+                              decoration: BoxDecoration(
+                                color: Colors.grey.shade100,
+                                borderRadius: BorderRadius.circular(10),
+                                border: Border.all(color: Colors.grey.shade300),
+                              ),
+                              child: Column(
+                                crossAxisAlignment: CrossAxisAlignment.start,
+                                children: [
+                                  Row(
+                                    children: [
+                                      Icon(Icons.description,
+                                          size: 40,
+                                          color: Colors.blue.shade700),
+                                      const SizedBox(width: 12),
+                                      Expanded(
+                                        child: Column(
+                                          crossAxisAlignment:
+                                              CrossAxisAlignment.start,
+                                          children: [
+                                            Text(
+                                              'Dokumen Berita Acara',
+                                              style: const TextStyle(
+                                                fontWeight: FontWeight.bold,
+                                              ),
+                                              maxLines: 1,
+                                              overflow: TextOverflow.ellipsis,
+                                            ),
+                                            Text(
+                                              Uri.parse(controller
+                                                      .selectedLaporan
+                                                      .value!
+                                                      .beritaAcaraUrl!)
+                                                  .pathSegments
+                                                  .last,
+                                              style: TextStyle(
+                                                fontSize: 12,
+                                                color: Colors.grey[600],
+                                              ),
+                                              maxLines: 1,
+                                              overflow: TextOverflow.ellipsis,
+                                            ),
+                                          ],
+                                        ),
+                                      ),
+                                    ],
+                                  ),
+                                  const SizedBox(height: 8),
+                                  Row(
+                                    mainAxisAlignment: MainAxisAlignment.end,
+                                    children: [
+                                      TextButton.icon(
+                                        onPressed: () =>
+                                            _pickBeritaAcaraFile(context),
+                                        icon: const Icon(Icons.edit,
+                                            color: Colors.blue),
+                                        label: const Text('Ganti',
+                                            style:
+                                                TextStyle(color: Colors.blue)),
+                                      ),
+                                    ],
+                                  ),
+                                ],
+                              ),
+                            )
+                          // Berita acara yang baru dipilih
+                          else if (controller.beritaAcaraPath.isNotEmpty)
+                            Container(
+                              width: double.infinity,
+                              padding: const EdgeInsets.all(12),
+                              decoration: BoxDecoration(
+                                color: Colors.grey.shade100,
+                                borderRadius: BorderRadius.circular(10),
+                                border: Border.all(color: Colors.grey.shade300),
+                              ),
+                              child: Column(
+                                crossAxisAlignment: CrossAxisAlignment.start,
+                                children: [
+                                  Row(
+                                    children: [
+                                      Icon(Icons.description,
+                                          size: 40,
+                                          color: Colors.blue.shade700),
+                                      const SizedBox(width: 12),
+                                      Expanded(
+                                        child: Column(
+                                          crossAxisAlignment:
+                                              CrossAxisAlignment.start,
+                                          children: [
+                                            Text(
+                                              File(controller
+                                                      .beritaAcaraPath.value)
+                                                  .path
+                                                  .split('/')
+                                                  .last,
+                                              style: const TextStyle(
+                                                fontWeight: FontWeight.bold,
+                                              ),
+                                              maxLines: 1,
+                                              overflow: TextOverflow.ellipsis,
+                                            ),
+                                            Text(
+                                              'Dokumen berita acara',
+                                              style: TextStyle(
+                                                fontSize: 12,
+                                                color: Colors.grey[600],
+                                              ),
+                                            ),
+                                          ],
+                                        ),
+                                      ),
+                                    ],
+                                  ),
+                                  const SizedBox(height: 8),
+                                  Row(
+                                    mainAxisAlignment: MainAxisAlignment.end,
+                                    children: [
+                                      TextButton.icon(
+                                        onPressed: () {
+                                          controller.beritaAcaraPath.value = '';
+                                        },
+                                        icon: const Icon(Icons.delete,
+                                            color: Colors.red),
+                                        label: const Text('Hapus',
+                                            style:
+                                                TextStyle(color: Colors.red)),
+                                      ),
+                                    ],
+                                  ),
+                                ],
+                              ),
+                            )
+                          // Tidak ada berita acara
+                          else
+                            OutlinedButton.icon(
+                              onPressed: () => _pickBeritaAcaraFile(context),
+                              icon: const Icon(Icons.upload_file),
+                              label: const Text('Upload Dokumen Berita Acara'),
+                              style: OutlinedButton.styleFrom(
+                                padding: const EdgeInsets.symmetric(
+                                  vertical: 12,
+                                  horizontal: 16,
+                                ),
+                                side: BorderSide(color: Colors.blue.shade300),
+                              ),
+                            ),
+                          const SizedBox(height: 4),
+                          Text(
+                            'Format dokumen: PDF, DOC, DOCX (maks. 10MB)',
+                            style: TextStyle(
+                              fontSize: 12,
+                              color: Colors.grey[600],
+                              fontStyle: FontStyle.italic,
+                            ),
+                          ),
+                        ],
+                      ),
+                    ],
+                  ),
+                ),
+              ),
+
+              const SizedBox(height: 32),
+
+              // Tombol aksi
+              Row(
+                children: [
+                  Expanded(
+                    child: OutlinedButton(
+                      onPressed: () => Get.back(),
+                      style: OutlinedButton.styleFrom(
+                        padding: const EdgeInsets.symmetric(vertical: 16),
+                        shape: RoundedRectangleBorder(
+                          borderRadius: BorderRadius.circular(10),
+                        ),
+                      ),
+                      child: const Text('Batal'),
+                    ),
+                  ),
+                  const SizedBox(width: 16),
+                  Expanded(
+                    child: Obx(() => ElevatedButton(
+                          onPressed: controller.isSaving.value
+                              ? null
+                              : () => controller.updateLaporan(laporanId),
+                          style: ElevatedButton.styleFrom(
+                            padding: const EdgeInsets.symmetric(vertical: 16),
+                            shape: RoundedRectangleBorder(
+                              borderRadius: BorderRadius.circular(10),
+                            ),
+                          ),
+                          child: controller.isSaving.value
+                              ? const SizedBox(
+                                  height: 20,
+                                  width: 20,
+                                  child:
+                                      CircularProgressIndicator(strokeWidth: 2),
+                                )
+                              : const Text(
+                                  'Simpan Perubahan',
+                                  style: TextStyle(
+                                    fontSize: 16,
+                                    fontWeight: FontWeight.bold,
+                                  ),
+                                ),
+                        )),
+                  ),
+                ],
+              ),
+            ],
+          ),
+        );
+      }),
+    );
+  }
+
+  // Widget untuk item informasi
+  Widget _buildInfoItem(String label, String value) {
+    return Padding(
+      padding: const EdgeInsets.only(bottom: 12),
+      child: Row(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          SizedBox(
+            width: 120,
+            child: Text(
+              label,
+              style: TextStyle(
+                fontSize: 14,
+                color: Colors.grey[700],
+              ),
+            ),
+          ),
+          const Text(' : '),
+          Expanded(
+            child: Text(
+              value,
+              style: const TextStyle(
+                fontSize: 14,
+                fontWeight: FontWeight.w500,
+              ),
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  // Widget untuk input teks
+  Widget _buildTextField({
+    required TextEditingController controller,
+    required String label,
+    required String hint,
+    int maxLines = 1,
+    bool required = false,
+  }) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        RichText(
+          text: TextSpan(
+            text: label,
+            style: TextStyle(
+              fontSize: 14,
+              fontWeight: FontWeight.w500,
+              color: Colors.grey[800],
+            ),
+            children: required
+                ? const [
+                    TextSpan(
+                      text: ' *',
+                      style: TextStyle(
+                        color: Colors.red,
+                        fontWeight: FontWeight.bold,
+                      ),
+                    ),
+                  ]
+                : null,
+          ),
+        ),
+        const SizedBox(height: 8),
+        TextField(
+          controller: controller,
+          decoration: InputDecoration(
+            hintText: hint,
+            border: OutlineInputBorder(
+              borderRadius: BorderRadius.circular(10),
+            ),
+            contentPadding: const EdgeInsets.symmetric(
+              horizontal: 16,
+              vertical: 12,
+            ),
+          ),
+          maxLines: maxLines,
+        ),
+      ],
+    );
+  }
+
+  // Metode untuk memilih gambar dokumentasi
+  Future<void> _pickDocumentationImage(BuildContext context) async {
+    try {
+      final ImagePicker picker = ImagePicker();
+      final XFile? image = await picker.pickImage(
+        source: ImageSource.gallery,
+        imageQuality: 80,
+      );
+
+      if (image != null) {
+        controller.dokumentasiPath.value = image.path;
+      }
+    } catch (e) {
+      ScaffoldMessenger.of(context).showSnackBar(
+        SnackBar(
+          content: Text('Terjadi kesalahan: $e'),
+          backgroundColor: Colors.red,
+        ),
+      );
+    }
+  }
+
+  // Metode untuk memilih file berita acara
+  Future<void> _pickBeritaAcaraFile(BuildContext context) async {
+    try {
+      FilePickerResult? result = await FilePicker.platform.pickFiles(
+        type: FileType.custom,
+        allowedExtensions: ['pdf', 'doc', 'docx'],
+      );
+
+      if (result != null) {
+        controller.beritaAcaraPath.value = result.files.single.path!;
+      }
+    } catch (e) {
+      ScaffoldMessenger.of(context).showSnackBar(
+        SnackBar(
+          content: Text('Terjadi kesalahan: $e'),
+          backgroundColor: Colors.red,
+        ),
+      );
+    }
+  }
+}
diff --git a/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_view.dart b/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_view.dart
new file mode 100644
index 0000000..d47f8bb
--- /dev/null
+++ b/lib/app/modules/laporan_penyaluran/views/laporan_penyaluran_view.dart
@@ -0,0 +1,410 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:penyaluran_app/app/data/models/laporan_penyaluran_model.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/controllers/laporan_penyaluran_controller.dart';
+import 'package:penyaluran_app/app/theme/app_theme.dart';
+import 'package:penyaluran_app/app/utils/date_time_helper.dart';
+import 'package:penyaluran_app/app/widgets/custom_app_bar.dart';
+import 'package:penyaluran_app/app/widgets/section_header.dart';
+import 'package:penyaluran_app/app/widgets/status_badge.dart';
+import 'package:intl/intl.dart';
+
+class LaporanPenyaluranView extends GetView<LaporanPenyaluranController> {
+  const LaporanPenyaluranView({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: CustomAppBar(
+        title: 'Laporan Penyaluran Bantuan',
+        showBackButton: true,
+      ),
+      body: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // Filter status
+          _buildStatusFilter(),
+
+          // Daftar laporan
+          Expanded(
+            child: Obx(() {
+              if (controller.isLoading.value) {
+                return const Center(child: CircularProgressIndicator());
+              }
+
+              if (controller.daftarLaporan.isEmpty) {
+                return Center(
+                  child: Column(
+                    mainAxisAlignment: MainAxisAlignment.center,
+                    children: [
+                      const Icon(Icons.note_alt_outlined,
+                          size: 64, color: Colors.grey),
+                      const SizedBox(height: 16),
+                      const Text(
+                        'Belum ada laporan penyaluran',
+                        style: TextStyle(
+                          fontSize: 16,
+                          fontWeight: FontWeight.bold,
+                        ),
+                      ),
+                      const SizedBox(height: 8),
+                      const Text(
+                        'Buat laporan baru untuk penyaluran yang telah selesai',
+                        textAlign: TextAlign.center,
+                        style: TextStyle(color: Colors.grey),
+                      ),
+                      const SizedBox(height: 24),
+                      ElevatedButton.icon(
+                        onPressed: () => _showPenyaluranDialog(context),
+                        icon: const Icon(Icons.add),
+                        label: const Text('Buat Laporan Baru'),
+                        style: ElevatedButton.styleFrom(
+                          padding: const EdgeInsets.symmetric(
+                              horizontal: 24, vertical: 12),
+                        ),
+                      ),
+                    ],
+                  ),
+                );
+              }
+
+              // Filter berdasarkan status jika dipilih
+              final filteredLaporan = controller.filterStatus.value == 'SEMUA'
+                  ? controller.daftarLaporan
+                  : controller.daftarLaporan
+                      .where((laporan) =>
+                          laporan.status == controller.filterStatus.value)
+                      .toList();
+
+              if (filteredLaporan.isEmpty) {
+                return Center(
+                  child: Text(
+                      'Tidak ada laporan dengan status ${controller.filterStatus.value}'),
+                );
+              }
+
+              return RefreshIndicator(
+                onRefresh: () async {
+                  await controller.fetchLaporan();
+                },
+                child: ListView.builder(
+                  padding: const EdgeInsets.all(16),
+                  itemCount: filteredLaporan.length,
+                  itemBuilder: (context, index) {
+                    final laporan = filteredLaporan[index];
+                    return _buildLaporanCard(context, laporan);
+                  },
+                ),
+              );
+            }),
+          ),
+        ],
+      ),
+      floatingActionButton: FloatingActionButton(
+        onPressed: () => _showPenyaluranDialog(context),
+        child: const Icon(Icons.add),
+      ),
+    );
+  }
+
+  // Widget untuk filter status
+  Widget _buildStatusFilter() {
+    return Container(
+      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
+      color: AppTheme.primaryColor.withOpacity(0.05),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          const SectionHeader(
+            title: 'Filter Status',
+            // subtitle: 'Tampilkan laporan berdasarkan status',
+            // showDivider: false,
+          ),
+          const SizedBox(height: 8),
+          SingleChildScrollView(
+            scrollDirection: Axis.horizontal,
+            child: Row(
+              children: [
+                _buildFilterChip('SEMUA'),
+                _buildFilterChip('DRAFT'),
+                _buildFilterChip('FINAL'),
+              ],
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  // Chip untuk filter
+  Widget _buildFilterChip(String status) {
+    return Obx(() {
+      final isSelected = controller.filterStatus.value == status;
+      return Padding(
+        padding: const EdgeInsets.only(right: 8),
+        child: FilterChip(
+          selected: isSelected,
+          label: Text(status),
+          onSelected: (_) {
+            controller.filterStatus.value = status;
+          },
+          backgroundColor: Colors.white,
+          checkmarkColor: Colors.white,
+          selectedColor: AppTheme.primaryColor,
+          labelStyle: TextStyle(
+            color: isSelected ? Colors.white : Colors.black,
+            fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
+          ),
+        ),
+      );
+    });
+  }
+
+  // Widget untuk card laporan
+  Widget _buildLaporanCard(
+      BuildContext context, LaporanPenyaluranModel laporan) {
+    return Card(
+      margin: const EdgeInsets.only(bottom: 16),
+      elevation: 3,
+      shape: RoundedRectangleBorder(
+        borderRadius: BorderRadius.circular(12),
+      ),
+      child: InkWell(
+        onTap: () {
+          Get.toNamed('/laporan-penyaluran/detail', arguments: laporan.id);
+        },
+        borderRadius: BorderRadius.circular(12),
+        child: Container(
+          decoration: BoxDecoration(
+            borderRadius: BorderRadius.circular(12),
+            gradient: AppTheme.primaryGradient,
+          ),
+          child: Padding(
+            padding: const EdgeInsets.all(16),
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                Row(
+                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                  children: [
+                    Expanded(
+                      child: Text(
+                        laporan.judul,
+                        style: const TextStyle(
+                          fontWeight: FontWeight.bold,
+                          fontSize: 16,
+                          color: Colors.white,
+                        ),
+                        maxLines: 2,
+                        overflow: TextOverflow.ellipsis,
+                      ),
+                    ),
+                    StatusBadge(status: laporan.status ?? 'DRAFT'),
+                  ],
+                ),
+                const Divider(height: 24, color: Colors.white30),
+                Row(
+                  children: [
+                    Icon(
+                      Icons.calendar_today,
+                      size: 16,
+                      color: Colors.white,
+                    ),
+                    const SizedBox(width: 6),
+                    Text(
+                      'Tanggal: ${laporan.tanggalLaporan != null ? DateTimeHelper.formatDateTime(laporan.tanggalLaporan!) : '-'}',
+                      style: TextStyle(
+                        fontSize: 12,
+                        color: Colors.white,
+                      ),
+                    ),
+                  ],
+                ),
+                const SizedBox(height: 16),
+                Row(
+                  mainAxisAlignment: MainAxisAlignment.end,
+                  children: [
+                    if (laporan.status == 'FINAL')
+                      Material(
+                        color: Colors.white.withOpacity(0.2),
+                        borderRadius: BorderRadius.circular(8),
+                        child: InkWell(
+                          borderRadius: BorderRadius.circular(8),
+                          onTap: () {
+                            controller
+                                .fetchPenyaluranDetail(
+                                    laporan.penyaluranBantuanId)
+                                .then((_) {
+                              if (controller.selectedPenyaluran.value != null) {
+                                controller.exportToPdf(laporan,
+                                    controller.selectedPenyaluran.value!);
+                              }
+                            });
+                          },
+                          child: Padding(
+                            padding: const EdgeInsets.symmetric(
+                                horizontal: 12, vertical: 6),
+                            child: Row(
+                              children: const [
+                                Icon(
+                                  Icons.picture_as_pdf,
+                                  size: 16,
+                                  color: Colors.white,
+                                ),
+                                SizedBox(width: 4),
+                                Text(
+                                  'Ekspor PDF',
+                                  style: TextStyle(
+                                    fontSize: 12,
+                                    color: Colors.white,
+                                    fontWeight: FontWeight.bold,
+                                  ),
+                                ),
+                              ],
+                            ),
+                          ),
+                        ),
+                      ),
+                    const SizedBox(width: 8),
+                    Material(
+                      color: Colors.orange.shade50,
+                      borderRadius: BorderRadius.circular(8),
+                      child: InkWell(
+                        borderRadius: BorderRadius.circular(8),
+                        onTap: () {
+                          Get.toNamed('/laporan-penyaluran/edit',
+                              arguments: laporan.id);
+                        },
+                        child: Padding(
+                          padding: const EdgeInsets.symmetric(
+                              horizontal: 12, vertical: 6),
+                          child: Row(
+                            children: const [
+                              Icon(Icons.edit, color: Colors.orange, size: 16),
+                              SizedBox(width: 4),
+                              Text('Edit',
+                                  style: TextStyle(
+                                      color: Colors.orange,
+                                      fontWeight: FontWeight.bold)),
+                            ],
+                          ),
+                        ),
+                      ),
+                    ),
+                    const SizedBox(width: 8),
+                    Material(
+                      color: Colors.red.shade50,
+                      borderRadius: BorderRadius.circular(8),
+                      child: InkWell(
+                        borderRadius: BorderRadius.circular(8),
+                        onTap: () {
+                          _showDeleteConfirmation(context, laporan.id!);
+                        },
+                        child: Padding(
+                          padding: const EdgeInsets.symmetric(
+                              horizontal: 12, vertical: 6),
+                          child: Row(
+                            children: const [
+                              Icon(Icons.delete, color: Colors.red, size: 16),
+                              SizedBox(width: 4),
+                              Text('Hapus',
+                                  style: TextStyle(
+                                      color: Colors.red,
+                                      fontWeight: FontWeight.bold)),
+                            ],
+                          ),
+                        ),
+                      ),
+                    ),
+                  ],
+                ),
+              ],
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+
+  // Dialog konfirmasi hapus laporan
+  void _showDeleteConfirmation(BuildContext context, String laporanId) {
+    showDialog(
+      context: context,
+      builder: (BuildContext context) {
+        return AlertDialog(
+          title: const Text('Hapus Laporan'),
+          content: const Text('Apakah Anda yakin ingin menghapus laporan ini?'),
+          actions: [
+            TextButton(
+              onPressed: () => Navigator.of(context).pop(),
+              child: const Text('Batal'),
+            ),
+            TextButton(
+              onPressed: () {
+                Navigator.of(context).pop();
+                controller.deleteLaporan(laporanId);
+              },
+              style: TextButton.styleFrom(foregroundColor: Colors.red),
+              child: const Text('Hapus'),
+            ),
+          ],
+        );
+      },
+    );
+  }
+
+  // Dialog pilih penyaluran untuk laporan baru
+  void _showPenyaluranDialog(BuildContext context) {
+    if (controller.penyaluranTanpaLaporan.isEmpty) {
+      Get.snackbar(
+        'Info',
+        'Tidak ada penyaluran yang tersedia untuk dibuat laporan. Pastikan ada penyaluran dengan status SELESAI.',
+        snackPosition: SnackPosition.BOTTOM,
+        backgroundColor: Colors.orange,
+        colorText: Colors.white,
+      );
+      return;
+    }
+
+    showDialog(
+      context: context,
+      builder: (BuildContext context) {
+        return AlertDialog(
+          title: const Text('Pilih Penyaluran'),
+          content: SizedBox(
+            width: double.maxFinite,
+            child: ListView.builder(
+              shrinkWrap: true,
+              itemCount: controller.penyaluranTanpaLaporan.length,
+              itemBuilder: (context, index) {
+                final penyaluran = controller.penyaluranTanpaLaporan[index];
+                return ListTile(
+                  title: Text(
+                    penyaluran.nama ??
+                        'Penyaluran #${penyaluran.id?.substring(0, 8)}',
+                    style: const TextStyle(fontWeight: FontWeight.bold),
+                  ),
+                  subtitle: Text(
+                    'Tanggal: ${penyaluran.tanggalSelesai != null ? DateFormat('dd/MM/yyyy').format(penyaluran.tanggalSelesai!) : '-'}',
+                  ),
+                  onTap: () {
+                    Navigator.of(context).pop();
+                    // Arahkan ke halaman buat laporan dengan ID penyaluran
+                    Get.toNamed('/laporan-penyaluran/create',
+                        arguments: penyaluran.id);
+                  },
+                );
+              },
+            ),
+          ),
+          actions: [
+            TextButton(
+              onPressed: () => Navigator.of(context).pop(),
+              child: const Text('Batal'),
+            ),
+          ],
+        );
+      },
+    );
+  }
+}
diff --git a/lib/app/modules/petugas_desa/bindings/petugas_desa_binding.dart b/lib/app/modules/petugas_desa/bindings/petugas_desa_binding.dart
index 6b3c913..9131efa 100644
--- a/lib/app/modules/petugas_desa/bindings/petugas_desa_binding.dart
+++ b/lib/app/modules/petugas_desa/bindings/petugas_desa_binding.dart
@@ -1,4 +1,5 @@
 import 'package:get/get.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/controllers/laporan_penyaluran_controller.dart';
 import 'package:penyaluran_app/app/modules/petugas_desa/controllers/petugas_desa_controller.dart';
 import 'package:penyaluran_app/app/modules/petugas_desa/controllers/petugas_desa_dashboard_controller.dart';
 import 'package:penyaluran_app/app/modules/petugas_desa/controllers/jadwal_penyaluran_controller.dart';
@@ -6,7 +7,6 @@ import 'package:penyaluran_app/app/modules/petugas_desa/controllers/stok_bantuan
 import 'package:penyaluran_app/app/modules/petugas_desa/controllers/penitipan_bantuan_controller.dart';
 import 'package:penyaluran_app/app/modules/petugas_desa/controllers/pengaduan_controller.dart';
 import 'package:penyaluran_app/app/modules/petugas_desa/controllers/penerima_bantuan_controller.dart';
-import 'package:penyaluran_app/app/modules/petugas_desa/controllers/laporan_controller.dart';
 import 'package:penyaluran_app/app/modules/auth/controllers/auth_controller.dart';
 import 'package:penyaluran_app/app/modules/petugas_desa/controllers/counter_service.dart';
 
@@ -60,8 +60,8 @@ class PetugasDesaBinding extends Bindings {
     );
 
     // Daftarkan controller laporan
-    Get.lazyPut<LaporanController>(
-      () => LaporanController(),
+    Get.lazyPut<LaporanPenyaluranController>(
+      () => LaporanPenyaluranController(),
     );
   }
 }
diff --git a/lib/app/modules/petugas_desa/controllers/detail_penyaluran_controller.dart b/lib/app/modules/petugas_desa/controllers/detail_penyaluran_controller.dart
index 7505271..de1136e 100644
--- a/lib/app/modules/petugas_desa/controllers/detail_penyaluran_controller.dart
+++ b/lib/app/modules/petugas_desa/controllers/detail_penyaluran_controller.dart
@@ -2,9 +2,11 @@ import 'package:get/get.dart';
 import 'package:penyaluran_app/app/data/models/penyaluran_bantuan_model.dart';
 import 'package:penyaluran_app/app/data/models/skema_bantuan_model.dart';
 import 'package:penyaluran_app/app/data/models/penerima_penyaluran_model.dart';
+import 'package:penyaluran_app/app/data/models/laporan_penyaluran_model.dart';
 import 'package:penyaluran_app/app/services/supabase_service.dart';
 import 'package:flutter/material.dart';
 import 'dart:io';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/controllers/laporan_penyaluran_controller.dart';
 
 class DetailPenyaluranController extends GetxController {
   final SupabaseService _supabaseService = Get.find<SupabaseService>();
@@ -14,10 +16,16 @@ class DetailPenyaluranController extends GetxController {
   final penyaluran = Rx<PenyaluranBantuanModel?>(null);
   final skemaBantuan = Rx<SkemaBantuanModel?>(null);
   final penerimaPenyaluran = <PenerimaPenyaluranModel>[].obs;
+  final laporan = Rx<LaporanPenyaluranModel?>(null);
+  final isLoadingLaporan = false.obs;
 
   // Status untuk mengetahui apakah petugas desa
   final isPetugasDesa = false.obs;
 
+  // Tambahkan referensi ke controller laporan
+  LaporanPenyaluranController? laporanController;
+  final RxBool isExporting = false.obs;
+
   @override
   void onInit() {
     super.onInit();
@@ -432,6 +440,9 @@ class DetailPenyaluranController extends GetxController {
       }
       penerimaPenyaluran.assignAll(penerima);
 
+      // Periksa apakah ada laporan untuk penyaluran ini
+      await checkLaporanPenyaluran(penyaluranId);
+
       // if (penerima.isNotEmpty) {
       //   print('DetailPenyaluranController - ID penerima: ${penerima[0].id}');
       // }
@@ -446,6 +457,57 @@ class DetailPenyaluranController extends GetxController {
     }
   }
 
+  Future<void> checkLaporanPenyaluran(String penyaluranId) async {
+    try {
+      isLoadingLaporan.value = true;
+
+      final response = await _supabaseService.client
+          .from('laporan_penyaluran')
+          .select('*')
+          .eq('penyaluran_bantuan_id', penyaluranId)
+          .maybeSingle();
+
+      if (response != null) {
+        // Laporan ditemukan
+        laporan.value = LaporanPenyaluranModel.fromJson(response);
+      } else {
+        // Tidak ada laporan
+        laporan.value = null;
+      }
+    } catch (e) {
+      print('Error saat memeriksa laporan penyaluran: $e');
+      laporan.value = null;
+    } finally {
+      isLoadingLaporan.value = false;
+    }
+  }
+
+  void navigateToLaporanCreate() {
+    if (penyaluran.value?.id == null) return;
+
+    // Kirim ID penyaluran langsung sebagai argument (String), bukan dalam bentuk Map
+    Get.toNamed('/laporan-penyaluran/create', arguments: penyaluran.value!.id)
+        ?.then((value) {
+      if (value == true) {
+        // Refresh data setelah membuat laporan
+        checkLaporanPenyaluran(penyaluran.value!.id!);
+      }
+    });
+  }
+
+  void navigateToLaporanDetail() {
+    if (laporan.value?.id == null) return;
+
+    // Navigasi ke halaman detail dengan mengirimkan ID sebagai argument
+    Get.toNamed('/laporan-penyaluran/detail', arguments: laporan.value!.id)
+        ?.then((value) {
+      if (value == true) {
+        // Refresh data setelah melihat detail laporan
+        checkLaporanPenyaluran(penyaluran.value!.id!);
+      }
+    });
+  }
+
   // Metode untuk verifikasi penerima berdasarkan QR code
   Future<bool> verifikasiPenerimaByQrCode(
       String penyaluranId, String qrHash) async {
@@ -498,4 +560,53 @@ class DetailPenyaluranController extends GetxController {
       isProcessing.value = false;
     }
   }
+
+  // Method untuk memuat controller laporan
+  Future<void> loadLaporanPenyaluranController() async {
+    if (laporanController == null) {
+      // Cek apakah controller sudah ada di Get
+      if (Get.isRegistered<LaporanPenyaluranController>()) {
+        laporanController = Get.find<LaporanPenyaluranController>();
+      } else {
+        // Jika belum ada, buat instance baru
+        laporanController = Get.put(LaporanPenyaluranController());
+      }
+    }
+
+    // Pastikan data laporan dimuat
+    if (laporan.value != null && penyaluran.value != null) {
+      await laporanController!.fetchLaporanDetail(laporan.value!.id!);
+    }
+  }
+
+  // Method untuk export PDF
+  Future<void> exportToPdf() async {
+    if (laporan.value == null || penyaluran.value == null) {
+      Get.snackbar(
+        'Error',
+        'Data laporan atau penyaluran tidak tersedia',
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+        snackPosition: SnackPosition.BOTTOM,
+      );
+      return;
+    }
+
+    isExporting.value = true;
+    try {
+      await loadLaporanPenyaluranController();
+      await laporanController!.exportToPdf(laporan.value!, penyaluran.value!);
+    } catch (e) {
+      print('Error saat export PDF: $e');
+      Get.snackbar(
+        'Error',
+        'Gagal mengekspor laporan ke PDF',
+        backgroundColor: Colors.red,
+        colorText: Colors.white,
+        snackPosition: SnackPosition.BOTTOM,
+      );
+    } finally {
+      isExporting.value = false;
+    }
+  }
 }
diff --git a/lib/app/modules/petugas_desa/controllers/laporan_controller.dart b/lib/app/modules/petugas_desa/controllers/laporan_controller.dart
deleted file mode 100644
index 8cb4bb2..0000000
--- a/lib/app/modules/petugas_desa/controllers/laporan_controller.dart
+++ /dev/null
@@ -1,197 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import 'package:penyaluran_app/app/data/models/laporan_model.dart';
-import 'package:penyaluran_app/app/data/models/user_model.dart';
-import 'package:penyaluran_app/app/modules/auth/controllers/auth_controller.dart';
-import 'package:penyaluran_app/app/services/supabase_service.dart';
-
-class LaporanController extends GetxController {
-  final AuthController _authController = Get.find<AuthController>();
-  final SupabaseService _supabaseService = SupabaseService.to;
-
-  final RxBool isLoading = false.obs;
-
-  // Indeks kategori yang dipilih untuk filter
-  final RxInt selectedCategoryIndex = 0.obs;
-
-  // Data untuk laporan
-  final RxList<LaporanModel> daftarLaporan = <LaporanModel>[].obs;
-
-  // Filter tanggal
-  final Rx<DateTime?> tanggalMulai = Rx<DateTime?>(null);
-  final Rx<DateTime?> tanggalSelesai = Rx<DateTime?>(null);
-
-  // Controller untuk pencarian
-  final TextEditingController searchController = TextEditingController();
-
-  UserModel? get user => _authController.user;
-
-  @override
-  void onInit() {
-    super.onInit();
-    // Set default tanggal filter (1 bulan terakhir)
-    tanggalSelesai.value = DateTime.now();
-    tanggalMulai.value = DateTime.now().subtract(const Duration(days: 30));
-    loadLaporanData();
-  }
-
-  @override
-  void onClose() {
-    searchController.dispose();
-    super.onClose();
-  }
-
-  Future<void> loadLaporanData() async {
-    isLoading.value = true;
-    try {
-      final laporanData = await _supabaseService.getLaporan(
-        tanggalMulai.value,
-        tanggalSelesai.value,
-      );
-      if (laporanData != null) {
-        daftarLaporan.value =
-            laporanData.map((data) => LaporanModel.fromJson(data)).toList();
-      }
-    } catch (e) {
-      print('Error loading laporan data: $e');
-    } finally {
-      isLoading.value = false;
-    }
-  }
-
-  Future<void> generateLaporan(String jenis) async {
-    isLoading.value = true;
-    try {
-      final laporan = LaporanModel(
-        jenis: jenis,
-        tanggalMulai: tanggalMulai.value,
-        tanggalSelesai: tanggalSelesai.value,
-        petugasId: user?.id,
-        createdAt: DateTime.now(),
-      );
-
-      final laporanId =
-          await _supabaseService.generateLaporan(laporan.toJson());
-
-      if (laporanId != null) {
-        await loadLaporanData();
-        Get.snackbar(
-          'Sukses',
-          'Laporan berhasil dibuat',
-          snackPosition: SnackPosition.TOP,
-          backgroundColor: Colors.green,
-          colorText: Colors.white,
-        );
-      }
-    } catch (e) {
-      print('Error generating laporan: $e');
-      Get.snackbar(
-        'Error',
-        'Gagal membuat laporan: ${e.toString()}',
-        snackPosition: SnackPosition.TOP,
-        backgroundColor: Colors.red,
-        colorText: Colors.white,
-      );
-    } finally {
-      isLoading.value = false;
-    }
-  }
-
-  Future<void> downloadLaporan(String laporanId) async {
-    isLoading.value = true;
-    try {
-      final url = await _supabaseService.downloadLaporan(laporanId);
-      if (url != null) {
-        // Implementasi download file
-        Get.snackbar(
-          'Sukses',
-          'Laporan berhasil diunduh',
-          snackPosition: SnackPosition.TOP,
-          backgroundColor: Colors.green,
-          colorText: Colors.white,
-        );
-      }
-    } catch (e) {
-      print('Error downloading laporan: $e');
-      Get.snackbar(
-        'Error',
-        'Gagal mengunduh laporan: ${e.toString()}',
-        snackPosition: SnackPosition.TOP,
-        backgroundColor: Colors.red,
-        colorText: Colors.white,
-      );
-    } finally {
-      isLoading.value = false;
-    }
-  }
-
-  Future<void> deleteLaporan(String laporanId) async {
-    isLoading.value = true;
-    try {
-      await _supabaseService.deleteLaporan(laporanId);
-      await loadLaporanData();
-      Get.snackbar(
-        'Sukses',
-        'Laporan berhasil dihapus',
-        snackPosition: SnackPosition.TOP,
-        backgroundColor: Colors.green,
-        colorText: Colors.white,
-      );
-    } catch (e) {
-      print('Error deleting laporan: $e');
-      Get.snackbar(
-        'Error',
-        'Gagal menghapus laporan: ${e.toString()}',
-        snackPosition: SnackPosition.TOP,
-        backgroundColor: Colors.red,
-        colorText: Colors.white,
-      );
-    } finally {
-      isLoading.value = false;
-    }
-  }
-
-  void setTanggalMulai(DateTime tanggal) {
-    tanggalMulai.value = tanggal;
-  }
-
-  void setTanggalSelesai(DateTime tanggal) {
-    tanggalSelesai.value = tanggal;
-  }
-
-  Future<void> applyFilter() async {
-    await loadLaporanData();
-  }
-
-  Future<void> refreshData() async {
-    isLoading.value = true;
-    try {
-      await loadLaporanData();
-    } finally {
-      isLoading.value = false;
-    }
-  }
-
-  void changeCategory(int index) {
-    selectedCategoryIndex.value = index;
-  }
-
-  List<LaporanModel> getFilteredLaporan() {
-    switch (selectedCategoryIndex.value) {
-      case 0:
-        return daftarLaporan;
-      case 1:
-        return daftarLaporan
-            .where((item) => item.jenis == 'PENYALURAN')
-            .toList();
-      case 2:
-        return daftarLaporan
-            .where((item) => item.jenis == 'STOK_BANTUAN')
-            .toList();
-      case 3:
-        return daftarLaporan.where((item) => item.jenis == 'PENERIMA').toList();
-      default:
-        return daftarLaporan;
-    }
-  }
-}
diff --git a/lib/app/modules/petugas_desa/views/detail_penyaluran_page.dart b/lib/app/modules/petugas_desa/views/detail_penyaluran_page.dart
index 4acbb3e..6af3e60 100644
--- a/lib/app/modules/petugas_desa/views/detail_penyaluran_page.dart
+++ b/lib/app/modules/petugas_desa/views/detail_penyaluran_page.dart
@@ -6,7 +6,6 @@ import 'package:penyaluran_app/app/theme/app_theme.dart';
 import 'package:penyaluran_app/app/utils/date_time_helper.dart';
 import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
 import 'package:penyaluran_app/app/modules/petugas_desa/views/konfirmasi_penerima_page.dart';
-import 'package:qr_flutter/qr_flutter.dart';
 import 'package:penyaluran_app/app/modules/petugas_desa/views/qr_scanner_page.dart';
 
 class DetailPenyaluranPage extends StatelessWidget {
@@ -69,6 +68,9 @@ class DetailPenyaluranPage extends StatelessWidget {
                     controller.penyaluran.value?.alasanPembatalan != null &&
                     controller.penyaluran.value!.alasanPembatalan!.isNotEmpty)
                   _buildPembatalanSection(context),
+                if (controller.penyaluran.value?.status?.toUpperCase() ==
+                    'TERLAKSANA')
+                  _buildLaporanSection(context),
                 const SizedBox(height: 16),
                 _buildPenerimaPenyaluranSection(context),
                 const SizedBox(height: 24),
@@ -1495,6 +1497,220 @@ class DetailPenyaluranPage extends StatelessWidget {
     );
   }
 
+  Widget _buildLaporanSection(BuildContext context) {
+    return Obx(() {
+      if (controller.isLoadingLaporan.value) {
+        return Card(
+          elevation: 2,
+          shape: RoundedRectangleBorder(
+            borderRadius: BorderRadius.circular(12),
+          ),
+          child: Container(
+            padding: const EdgeInsets.all(16),
+            child: const Center(
+              child: Column(
+                mainAxisSize: MainAxisSize.min,
+                children: [
+                  CircularProgressIndicator(),
+                  SizedBox(height: 8),
+                  Text('Memuat data laporan...'),
+                ],
+              ),
+            ),
+          ),
+        );
+      }
+
+      return Card(
+        elevation: 2,
+        shape: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(12),
+        ),
+        child: Padding(
+          padding: const EdgeInsets.all(16.0),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Row(
+                mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                children: [
+                  Row(
+                    children: [
+                      const Icon(
+                        Icons.description_outlined,
+                        color: AppTheme.successColor,
+                        size: 24,
+                      ),
+                      const SizedBox(width: 8),
+                      const Text(
+                        'Laporan Penyaluran',
+                        style: TextStyle(
+                          fontSize: 18,
+                          fontWeight: FontWeight.bold,
+                          color: AppTheme.successColor,
+                        ),
+                      ),
+                    ],
+                  ),
+                  if (controller.laporan.value != null)
+                    Container(
+                      padding: const EdgeInsets.symmetric(
+                          horizontal: 12, vertical: 6),
+                      decoration: BoxDecoration(
+                        color: AppTheme.successColor.withOpacity(0.1),
+                        borderRadius: BorderRadius.circular(20),
+                        border: Border.all(
+                          color: AppTheme.successColor.withOpacity(0.3),
+                        ),
+                      ),
+                      child: Row(
+                        children: [
+                          Icon(
+                            Icons.check_circle,
+                            color: AppTheme.successColor,
+                            size: 16,
+                          ),
+                          const SizedBox(width: 4),
+                          Text(
+                            'Tersedia',
+                            style: TextStyle(
+                              fontSize: 12,
+                              fontWeight: FontWeight.bold,
+                              color: AppTheme.successColor,
+                            ),
+                          ),
+                        ],
+                      ),
+                    ),
+                ],
+              ),
+              const Divider(height: 24),
+              if (controller.laporan.value == null)
+                Column(
+                  children: [
+                    Center(
+                      child: Column(
+                        mainAxisSize: MainAxisSize.min,
+                        children: [
+                          Icon(
+                            Icons.assignment_late_outlined,
+                            size: 50,
+                            color: Colors.grey.shade400,
+                          ),
+                          const SizedBox(height: 16),
+                          Text(
+                            'Belum ada laporan penyaluran',
+                            style: TextStyle(
+                              fontSize: 16,
+                              fontWeight: FontWeight.bold,
+                              color: Colors.grey.shade600,
+                            ),
+                          ),
+                          const SizedBox(height: 8),
+                          Text(
+                            'Buat laporan untuk mendokumentasikan hasil penyaluran bantuan',
+                            textAlign: TextAlign.center,
+                            style: TextStyle(
+                              fontSize: 14,
+                              color: Colors.grey.shade500,
+                            ),
+                          ),
+                          const SizedBox(height: 20),
+                          ElevatedButton.icon(
+                            onPressed: controller.navigateToLaporanCreate,
+                            icon: const Icon(Icons.add_circle_outline),
+                            label: const Text('Buat Laporan'),
+                            style: ElevatedButton.styleFrom(
+                              backgroundColor: AppTheme.primaryColor,
+                              foregroundColor: Colors.white,
+                              padding: const EdgeInsets.symmetric(
+                                horizontal: 24,
+                                vertical: 12,
+                              ),
+                              shape: RoundedRectangleBorder(
+                                borderRadius: BorderRadius.circular(8),
+                              ),
+                            ),
+                          ),
+                        ],
+                      ),
+                    ),
+                  ],
+                )
+              else
+                Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    _buildInfoRow('Judul', controller.laporan.value!.judul),
+                    _buildInfoRow(
+                      'Tanggal Laporan',
+                      controller.laporan.value?.tanggalLaporan != null
+                          ? DateTimeHelper.formatDateTime(
+                              controller.laporan.value!.tanggalLaporan!)
+                          : '-',
+                    ),
+                    const SizedBox(height: 16),
+                    Row(
+                      children: [
+                        Expanded(
+                          child: OutlinedButton.icon(
+                            onPressed: () =>
+                                controller.navigateToLaporanDetail(),
+                            icon: const Icon(Icons.visibility),
+                            label: const Text('Lihat Detail'),
+                            style: OutlinedButton.styleFrom(
+                              foregroundColor: AppTheme.primaryColor,
+                              side: const BorderSide(
+                                  color: AppTheme.primaryColor),
+                              padding: const EdgeInsets.symmetric(vertical: 12),
+                            ),
+                          ),
+                        ),
+                        const SizedBox(width: 12),
+                        if (controller.laporan.value?.beritaAcaraUrl != null &&
+                            controller
+                                .laporan.value!.beritaAcaraUrl!.isNotEmpty)
+                          Expanded(
+                            child: Obx(() => ElevatedButton.icon(
+                                  onPressed: controller.isExporting.value
+                                      ? null
+                                      : () => controller.exportToPdf(),
+                                  icon: controller.isExporting.value
+                                      ? SizedBox(
+                                          width: 20,
+                                          height: 20,
+                                          child: CircularProgressIndicator(
+                                            strokeWidth: 2,
+                                            valueColor:
+                                                AlwaysStoppedAnimation<Color>(
+                                                    Colors.white),
+                                          ),
+                                        )
+                                      : const Icon(Icons.download),
+                                  label: Text(controller.isExporting.value
+                                      ? 'Mengekspor...'
+                                      : 'Unduh PDF'),
+                                  style: ElevatedButton.styleFrom(
+                                    backgroundColor: AppTheme.successColor,
+                                    foregroundColor: Colors.white,
+                                    padding: const EdgeInsets.symmetric(
+                                        vertical: 12),
+                                    disabledBackgroundColor:
+                                        AppTheme.successColor.withOpacity(0.7),
+                                  ),
+                                )),
+                          ),
+                      ],
+                    ),
+                  ],
+                ),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+
   List<PenerimaPenyaluranModel> _getFilteredPenerima() {
     final query = searchQuery.value;
     final status = statusFilter.value;
diff --git a/lib/app/modules/petugas_desa/views/petugas_desa_view.dart b/lib/app/modules/petugas_desa/views/petugas_desa_view.dart
index 942d4ca..f0c532b 100644
--- a/lib/app/modules/petugas_desa/views/petugas_desa_view.dart
+++ b/lib/app/modules/petugas_desa/views/petugas_desa_view.dart
@@ -179,18 +179,25 @@ class PetugasDesaView extends GetView<PetugasDesaController> {
               crossAxisAlignment: CrossAxisAlignment.start,
               mainAxisAlignment: MainAxisAlignment.end,
               children: [
-                const CircleAvatar(
+                CircleAvatar(
                   radius: 30,
                   backgroundColor: Colors.white,
-                  child: Icon(
-                    Icons.person,
-                    size: 40,
-                    color: AppTheme.primaryColor,
-                  ),
+                  backgroundImage: controller.user?.avatar != null &&
+                          controller.user!.avatar!.isNotEmpty
+                      ? NetworkImage(controller.user!.avatar!)
+                      : null,
+                  child: controller.user?.avatar == null ||
+                          controller.user!.avatar!.isEmpty
+                      ? const Icon(
+                          Icons.person,
+                          size: 40,
+                          color: AppTheme.primaryColor,
+                        )
+                      : null,
                 ),
                 const SizedBox(height: 10),
                 Text(
-                  controller.nama,
+                  controller.user?.name ?? 'Petugas Desa',
                   style: const TextStyle(
                     color: Colors.white,
                     fontSize: 18,
@@ -198,203 +205,106 @@ class PetugasDesaView extends GetView<PetugasDesaController> {
                   ),
                 ),
                 Text(
-                  'Petugas Desa',
+                  controller.user?.desa?.nama != null
+                      ? '${controller.user?.role} - ${controller.user!.desa!.nama}'
+                      : controller.user?.role ?? 'PETUGAS_DESA',
                   style: TextStyle(
-                    color: Colors.white.withOpacity(0.8),
+                    color: Colors.white.withAlpha(200),
                     fontSize: 14,
                   ),
                 ),
               ],
             ),
           ),
-          Obx(() => ListTile(
-                leading: const Icon(Icons.dashboard_outlined),
-                title: const Text('Dashboard'),
-                selected: controller.activeTabIndex.value == 0,
-                selectedColor: AppTheme.primaryColor,
-                onTap: () {
-                  controller.changeTab(0);
-                  Navigator.pop(context);
-                },
-              )),
-          Obx(() => ListTile(
-                leading: const Icon(Icons.calendar_today_outlined),
-                title: const Text('Penyaluran'),
-                selected: controller.activeTabIndex.value == 1,
-                selectedColor: AppTheme.primaryColor,
-                onTap: () {
-                  controller.changeTab(1);
-                  Navigator.pop(context);
-                },
-              )),
-          Obx(() => ListTile(
-                leading: Stack(
-                  alignment: Alignment.center,
-                  children: [
-                    const Icon(Icons.handshake_outlined),
-                    if (controller.jumlahMenunggu.value > 0)
-                      Positioned(
-                        top: 0,
-                        right: 0,
-                        child: Container(
-                          padding: const EdgeInsets.all(2),
-                          decoration: BoxDecoration(
-                            color: Colors.orange,
-                            borderRadius: BorderRadius.circular(10),
-                          ),
-                          constraints: const BoxConstraints(
-                            minWidth: 12,
-                            minHeight: 12,
-                          ),
-                          child: Text(
-                            controller.jumlahMenunggu.value.toString(),
-                            style: const TextStyle(
-                              color: Colors.white,
-                              fontSize: 8,
-                            ),
-                            textAlign: TextAlign.center,
-                          ),
-                        ),
-                      ),
-                  ],
-                ),
-                title: const Text('Penitipan'),
-                selected: controller.activeTabIndex.value == 2,
-                selectedColor: AppTheme.primaryColor,
-                onTap: () {
-                  controller.changeTab(2);
-                  Navigator.pop(context);
-                },
-              )),
-          Obx(() {
-            final int jumlahPengaduanDiproses = controller.jumlahDiproses.value;
-
-            return ListTile(
-              leading: Stack(
-                alignment: Alignment.center,
-                children: [
-                  const Icon(Icons.report_problem_outlined),
-                  // Selalu tampilkan badge untuk debugging
-                  Positioned(
-                    top: 0,
-                    right: 0,
-                    child: Container(
-                      padding: const EdgeInsets.all(2),
-                      decoration: BoxDecoration(
-                        color: Colors.red,
-                        borderRadius: BorderRadius.circular(10),
-                      ),
-                      constraints: const BoxConstraints(
-                        minWidth: 12,
-                        minHeight: 12,
-                      ),
-                      child: Text(
-                        jumlahPengaduanDiproses.toString(),
-                        style: const TextStyle(
-                          color: Colors.white,
-                          fontSize: 8,
-                        ),
-                        textAlign: TextAlign.center,
-                      ),
-                    ),
-                  ),
-                ],
-              ),
-              title: const Text('Pengaduan'),
-              selected: controller.activeTabIndex.value == 3,
-              selectedColor: AppTheme.primaryColor,
-              onTap: () {
-                controller.changeTab(3);
-                Navigator.pop(context);
-              },
-            );
-          }),
-          Obx(() => ListTile(
-                leading: const Icon(Icons.inventory_2_outlined),
-                title: const Text('Stok Bantuan'),
-                selected: controller.activeTabIndex.value == 4,
-                selectedColor: AppTheme.primaryColor,
-                onTap: () {
-                  controller.changeTab(4);
-                  Navigator.pop(context);
-                },
-              )),
-          const Divider(),
           ListTile(
-            leading: const Icon(Icons.people_outline),
-            title: const Text('Daftar Penerima'),
+            leading: const Icon(Icons.dashboard_outlined),
+            title: const Text('Dashboard'),
+            selected: controller.activeTabIndex.value == 0,
+            selectedColor: AppTheme.primaryColor,
             onTap: () {
-              Navigator.pop(context); // Tutup drawer terlebih dahulu
+              Navigator.pop(context);
+              controller.changeTab(0);
+            },
+          ),
+          ListTile(
+            leading: const Icon(Icons.handshake_outlined),
+            title: const Text('Penyaluran'),
+            selected: controller.activeTabIndex.value == 1,
+            selectedColor: AppTheme.primaryColor,
+            onTap: () {
+              Navigator.pop(context);
+              controller.changeTab(1);
+            },
+          ),
+          ListTile(
+            leading: const Icon(Icons.inventory_2_outlined),
+            title: const Text('Penitipan'),
+            selected: controller.activeTabIndex.value == 2,
+            selectedColor: AppTheme.primaryColor,
+            onTap: () {
+              Navigator.pop(context);
+              controller.changeTab(2);
+            },
+          ),
+          Obx(() => ListTile(
+                leading: controller.jumlahDiproses.value > 0
+                    ? Badge(
+                        label: Text(controller.jumlahDiproses.value.toString()),
+                        backgroundColor: Colors.red,
+                        child: const Icon(Icons.support_outlined),
+                      )
+                    : const Icon(Icons.support_outlined),
+                title: const Text('Pengaduan'),
+                selected: controller.activeTabIndex.value == 3,
+                selectedColor: AppTheme.primaryColor,
+                onTap: () {
+                  Navigator.pop(context);
+                  controller.changeTab(3);
+                },
+              )),
+          ListTile(
+            leading: const Icon(Icons.inventory_outlined),
+            title: const Text('Stok Bantuan'),
+            selected: controller.activeTabIndex.value == 4,
+            selectedColor: AppTheme.primaryColor,
+            onTap: () {
+              Navigator.pop(context);
+              controller.changeTab(4);
+            },
+          ),
+          ListTile(
+            leading: const Icon(Icons.person_add_outlined),
+            title: const Text('Kelola Penerima'),
+            onTap: () {
+              Navigator.pop(context);
               Get.toNamed('/daftar-penerima');
             },
           ),
           ListTile(
-            leading: const Icon(Icons.volunteer_activism_outlined),
-            title: const Text('Daftar Donatur'),
+            leading: const Icon(Icons.people_outlined),
+            title: const Text('Kelola Donatur'),
             onTap: () {
-              Navigator.pop(context); // Tutup drawer terlebih dahulu
+              Navigator.pop(context);
               Get.toNamed('/daftar-donatur');
             },
           ),
           ListTile(
-            leading: Stack(
-              alignment: Alignment.center,
-              children: [
-                const Icon(Icons.notifications_outlined),
-                if (controller.jumlahNotifikasiBelumDibaca.value > 0)
-                  Positioned(
-                    top: 0,
-                    right: 0,
-                    child: Container(
-                      padding: const EdgeInsets.all(2),
-                      decoration: BoxDecoration(
-                        color: Colors.red,
-                        borderRadius: BorderRadius.circular(10),
-                      ),
-                      constraints: const BoxConstraints(
-                        minWidth: 12,
-                        minHeight: 12,
-                      ),
-                      child: Text(
-                        controller.jumlahNotifikasiBelumDibaca.value.toString(),
-                        style: const TextStyle(
-                          color: Colors.white,
-                          fontSize: 8,
-                        ),
-                        textAlign: TextAlign.center,
-                      ),
-                    ),
-                  ),
-              ],
-            ),
-            title: const Text('Notifikasi'),
+            leading: const Icon(Icons.description_outlined),
+            title: const Text('Laporan Penyaluran'),
             onTap: () {
-              Navigator.pop(context); // Tutup drawer terlebih dahulu
-              Navigator.push(
-                context,
-                MaterialPageRoute(
-                  builder: (context) => const NotifikasiView(),
-                ),
-              );
+              Navigator.pop(context);
+              Get.toNamed('/laporan-penyaluran');
             },
           ),
+          const Divider(),
           ListTile(
             leading: const Icon(Icons.person_outline),
             title: const Text('Profil'),
             onTap: () {
-              // Navigasi ke halaman profil
               Navigator.pop(context);
               Get.toNamed('/profile');
             },
           ),
-          ListTile(
-            leading: const Icon(Icons.settings_outlined),
-            title: const Text('Pengaturan'),
-            onTap: () {
-              // Navigasi ke halaman pengaturan
-              Navigator.pop(context);
-            },
-          ),
           ListTile(
             leading: const Icon(Icons.logout),
             title: const Text('Keluar'),
diff --git a/lib/app/modules/petugas_desa/views/riwayat_penyaluran_view.dart b/lib/app/modules/petugas_desa/views/riwayat_penyaluran_view.dart
index af5dc15..f54f486 100644
--- a/lib/app/modules/petugas_desa/views/riwayat_penyaluran_view.dart
+++ b/lib/app/modules/petugas_desa/views/riwayat_penyaluran_view.dart
@@ -98,7 +98,7 @@ class RiwayatPenyaluranView extends GetView<JadwalPenyaluranController> {
                       mainAxisAlignment: MainAxisAlignment.spaceBetween,
                       children: [
                         Text(
-                          'Daftar Penyaluran ${status == 'TERLAKSANA' ? 'terlaksana' : 'batal terlaksana'}',
+                          'Daftar Penyaluran ${status == 'TERLAKSANA' ? 'Terlaksana' : 'Batal'}',
                           style:
                               Theme.of(context).textTheme.titleLarge?.copyWith(
                                     fontWeight: FontWeight.bold,
diff --git a/lib/app/modules/warga/views/warga_view.dart b/lib/app/modules/warga/views/warga_view.dart
index dd0db9f..c76e064 100644
--- a/lib/app/modules/warga/views/warga_view.dart
+++ b/lib/app/modules/warga/views/warga_view.dart
@@ -108,6 +108,11 @@ class WargaView extends GetView<WargaDashboardController> {
                 badgeColor: Colors.orange,
                 onTap: () => controller.changeTab(2),
               ),
+              DrawerMenuItem(
+                icon: Icons.description_outlined,
+                title: 'Laporan Penyaluran',
+                onTap: () => Get.toNamed('/laporan-penyaluran'),
+              ),
             ],
           )),
       body: Obx(() {
diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart
index 6b6f2dc..562f510 100644
--- a/lib/app/routes/app_pages.dart
+++ b/lib/app/routes/app_pages.dart
@@ -31,6 +31,11 @@ import 'package:penyaluran_app/app/modules/warga/views/warga_detail_penerimaan_v
 import 'package:penyaluran_app/app/modules/petugas_desa/views/detail_pengaduan_view.dart';
 import 'package:penyaluran_app/app/modules/petugas_desa/bindings/pengaduan_binding.dart';
 import 'package:penyaluran_app/app/modules/warga/views/detail_pengaduan_view.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/views/laporan_penyaluran_view.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/views/laporan_penyaluran_detail_view.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/views/laporan_penyaluran_create_view.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/views/laporan_penyaluran_edit_view.dart';
+import 'package:penyaluran_app/app/modules/laporan_penyaluran/bindings/laporan_penyaluran_binding.dart';
 
 part 'app_routes.dart';
 
@@ -148,6 +153,26 @@ class AppPages {
       page: () => const RiwayatPengaduanView(),
       binding: RiwayatPengaduanBinding(),
     ),
+    GetPage(
+      name: _Paths.laporanPenyaluran,
+      page: () => const LaporanPenyaluranView(),
+      binding: LaporanPenyaluranBinding(),
+    ),
+    GetPage(
+      name: _Paths.laporanPenyaluran + '/detail',
+      page: () => const LaporanPenyaluranDetailView(),
+      binding: LaporanPenyaluranBinding(),
+    ),
+    GetPage(
+      name: _Paths.laporanPenyaluran + '/create',
+      page: () => const LaporanPenyaluranCreateView(),
+      binding: LaporanPenyaluranBinding(),
+    ),
+    GetPage(
+      name: _Paths.laporanPenyaluran + '/edit',
+      page: () => const LaporanPenyaluranEditView(),
+      binding: LaporanPenyaluranBinding(),
+    ),
     GetPage(
       name: _Paths.qrScanner,
       page: () => QrScannerPage(penyaluranId: Get.parameters['id'] ?? ''),
diff --git a/lib/app/widgets/custom_app_bar.dart b/lib/app/widgets/custom_app_bar.dart
index 6393438..913967f 100644
--- a/lib/app/widgets/custom_app_bar.dart
+++ b/lib/app/widgets/custom_app_bar.dart
@@ -1,6 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:penyaluran_app/app/theme/app_colors.dart';
+import 'package:penyaluran_app/app/theme/app_theme.dart';
 
 /// AppBar kustom yang digunakan di seluruh aplikasi
 ///
@@ -60,7 +60,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
       ),
       centerTitle: centerTitle,
       elevation: elevation,
-      backgroundColor: backgroundColor ?? AppColors.primary,
+      backgroundColor: backgroundColor ?? AppTheme.primaryColor,
       foregroundColor: foregroundColor ?? Colors.white,
       leading: _buildLeading(),
       actions: actions,
diff --git a/lib/app/widgets/status_badge.dart b/lib/app/widgets/status_badge.dart
index dff4d5f..3d59662 100644
--- a/lib/app/widgets/status_badge.dart
+++ b/lib/app/widgets/status_badge.dart
@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
+import 'package:penyaluran_app/app/theme/app_theme.dart';
 
 class StatusBadge extends StatelessWidget {
   final String status;
@@ -20,20 +21,22 @@ class StatusBadge extends StatelessWidget {
   Widget build(BuildContext context) {
     final String statusUpper = status.toUpperCase();
 
-    // Default colors for common statuses
+    // Default colors for common statuses menggunakan AppTheme
     final Map<String, Color> defaultColors = {
-      'DITERIMA': Colors.green,
-      'MENUNGGU': Colors.orange,
-      'DITOLAK': Colors.red,
-      'PROSES': Colors.orange,
-      'DIPROSES': Colors.orange,
-      'TINDAKAN': Colors.orange,
-      'SELESAI': Colors.green,
-      'TERVERIFIKASI': Colors.green,
-      'BELUMMENERIMA': Colors.orange,
-      'DIJADWALKAN': Colors.blue,
-      'TERLAKSANA': Colors.purple,
-      'AKTIF': Colors.green,
+      'DITERIMA': AppTheme.verifiedColor,
+      'MENUNGGU': AppTheme.processedColor,
+      'DITOLAK': AppTheme.rejectedColor,
+      'PROSES': AppTheme.processedColor,
+      'DIPROSES': AppTheme.processedColor,
+      'TINDAKAN': AppTheme.processedColor,
+      'SELESAI': AppTheme.completedColor,
+      'TERVERIFIKASI': AppTheme.verifiedColor,
+      'BELUMMENERIMA': AppTheme.processedColor,
+      'DIJADWALKAN': AppTheme.scheduledColor,
+      'TERLAKSANA': AppTheme.completedColor,
+      'AKTIF': AppTheme.verifiedColor,
+      'DRAFT': AppTheme.processedColor,
+      'FINAL': AppTheme.completedColor,
     };
 
     // Default labels for common statuses
@@ -50,6 +53,8 @@ class StatusBadge extends StatelessWidget {
       'DIJADWALKAN': 'Dijadwalkan',
       'TERLAKSANA': 'Terlaksana',
       'AKTIF': 'Aktif',
+      'DRAFT': 'Draft',
+      'FINAL': 'Final',
     };
 
     // Determine color and label based on status
diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc
index ea3bde6..2ea3ef0 100644
--- a/linux/flutter/generated_plugin_registrant.cc
+++ b/linux/flutter/generated_plugin_registrant.cc
@@ -9,6 +9,7 @@
 #include <file_selector_linux/file_selector_plugin.h>
 #include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
 #include <gtk/gtk_plugin.h>
+#include <open_file_linux/open_file_linux_plugin.h>
 #include <url_launcher_linux/url_launcher_plugin.h>
 
 void fl_register_plugins(FlPluginRegistry* registry) {
@@ -21,6 +22,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
   g_autoptr(FlPluginRegistrar) gtk_registrar =
       fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin");
   gtk_plugin_register_with_registrar(gtk_registrar);
+  g_autoptr(FlPluginRegistrar) open_file_linux_registrar =
+      fl_plugin_registry_get_registrar_for_plugin(registry, "OpenFileLinuxPlugin");
+  open_file_linux_plugin_register_with_registrar(open_file_linux_registrar);
   g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
       fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
   url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake
index 0420466..bc9a32d 100644
--- a/linux/flutter/generated_plugins.cmake
+++ b/linux/flutter/generated_plugins.cmake
@@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
   file_selector_linux
   flutter_secure_storage_linux
   gtk
+  open_file_linux
   url_launcher_linux
 )
 
diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift
index 4188def..8c2961c 100644
--- a/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -6,16 +6,20 @@ import FlutterMacOS
 import Foundation
 
 import app_links
+import file_picker
 import file_selector_macos
 import flutter_secure_storage_macos
+import open_file_mac
 import path_provider_foundation
 import shared_preferences_foundation
 import url_launcher_macos
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
   AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
+  FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
   FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
   FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
+  OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
   PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
   SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
   UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
diff --git a/pubspec.lock b/pubspec.lock
index 2203e56..00ea691 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -57,6 +57,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.12.0"
+  barcode:
+    dependency: transitive
+    description:
+      name: barcode
+      sha256: "7b6729c37e3b7f34233e2318d866e8c48ddb46c1f7ad01ff7bb2a8de1da2b9f4"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.9"
+  bidi:
+    dependency: transitive
+    description:
+      name: bidi
+      sha256: "9a712c7ddf708f7c41b1923aa83648a3ed44cfd75b04f72d598c45e5be287f9d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.12"
   boolean_selector:
     dependency: transitive
     description:
@@ -153,6 +169,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "7.0.1"
+  file_picker:
+    dependency: "direct main"
+    description:
+      name: file_picker
+      sha256: "8d938fd5c11dc81bf1acd4f7f0486c683fe9e79a0b13419e27730f9ce4d8a25b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "9.2.1"
   file_selector_linux:
     dependency: transitive
     description:
@@ -350,7 +374,7 @@ packages:
     source: hosted
     version: "2.1.0"
   http:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: http
       sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
@@ -533,6 +557,70 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.0.0"
+  open_file:
+    dependency: "direct main"
+    description:
+      name: open_file
+      sha256: d17e2bddf5b278cb2ae18393d0496aa4f162142ba97d1a9e0c30d476adf99c0e
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.5.10"
+  open_file_android:
+    dependency: transitive
+    description:
+      name: open_file_android
+      sha256: "58141fcaece2f453a9684509a7275f231ac0e3d6ceb9a5e6de310a7dff9084aa"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.6"
+  open_file_ios:
+    dependency: transitive
+    description:
+      name: open_file_ios
+      sha256: "02996f01e5f6863832068e97f8f3a5ef9b613516db6897f373b43b79849e4d07"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.3"
+  open_file_linux:
+    dependency: transitive
+    description:
+      name: open_file_linux
+      sha256: d189f799eecbb139c97f8bc7d303f9e720954fa4e0fa1b0b7294767e5f2d7550
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.0.5"
+  open_file_mac:
+    dependency: transitive
+    description:
+      name: open_file_mac
+      sha256: "1440b1e37ceb0642208cfeb2c659c6cda27b25187a90635c9d1acb7d0584d324"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.3"
+  open_file_platform_interface:
+    dependency: transitive
+    description:
+      name: open_file_platform_interface
+      sha256: "101b424ca359632699a7e1213e83d025722ab668b9fd1412338221bf9b0e5757"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.3"
+  open_file_web:
+    dependency: transitive
+    description:
+      name: open_file_web
+      sha256: e3dbc9584856283dcb30aef5720558b90f88036360bd078e494ab80a80130c4f
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.0.4"
+  open_file_windows:
+    dependency: transitive
+    description:
+      name: open_file_windows
+      sha256: d26c31ddf935a94a1a3aa43a23f4fff8a5ff4eea395fe7a8cb819cf55431c875
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.0.3"
   path:
     dependency: transitive
     description:
@@ -550,7 +638,7 @@ packages:
     source: hosted
     version: "1.1.0"
   path_provider:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: path_provider
       sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
@@ -597,6 +685,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.3.0"
+  pdf:
+    dependency: "direct main"
+    description:
+      name: pdf
+      sha256: "28eacad99bffcce2e05bba24e50153890ad0255294f4dd78a17075a2ba5c8416"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.11.3"
   petitparser:
     dependency: transitive
     description:
@@ -814,34 +910,34 @@ packages:
     dependency: "direct main"
     description:
       name: syncfusion_flutter_calendar
-      sha256: "11b01bc7ad1d240d7c644081bda79e61c0a8d26eec7eba67bfc7274310562897"
+      sha256: "87761c6e73997d8d39181741f9e6244daf29b521aafaccf46b1bf31e86767a3f"
       url: "https://pub.dev"
     source: hosted
-    version: "28.2.11"
+    version: "28.2.12"
   syncfusion_flutter_core:
     dependency: transitive
     description:
       name: syncfusion_flutter_core
-      sha256: "59b6d2a7deacade6129d2f15615ca49ed56278fea055cd2e52cace78a343dd5e"
+      sha256: f1d2b52697543e13bdefdc62d15868124a265987577f53224a7dbe176c8448f0
       url: "https://pub.dev"
     source: hosted
-    version: "28.2.11"
+    version: "28.2.12"
   syncfusion_flutter_datepicker:
     dependency: transitive
     description:
       name: syncfusion_flutter_datepicker
-      sha256: "73ece73742f123c750d674461c6902cbdf32fbd695c15fdf7e8487d290bb7179"
+      sha256: cfc91ebacee63b2c5220e541736f8df211d4f0bfbf34265778862ae20faf094f
       url: "https://pub.dev"
     source: hosted
-    version: "28.2.11+1"
+    version: "28.2.12"
   syncfusion_localizations:
     dependency: "direct main"
     description:
       name: syncfusion_localizations
-      sha256: "04bddcd326628ae3aea227d86534b1682e893674df3474fc71c83e0bffb27325"
+      sha256: "383f0bbd80cdd1bf37c72a4ff3fb0cb476f34e753dab4dd146ae57578fb1fa50"
       url: "https://pub.dev"
     source: hosted
-    version: "28.2.11"
+    version: "28.2.12"
   term_glyph:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 29f12b8..9dbb929 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -30,6 +30,7 @@ environment:
 dependencies:
   flutter:
     sdk: flutter
+  http: ^1.3.0 # atau versi yang lebih baru
 
   # The following adds the Cupertino Icons font to your application.
   # Use with the CupertinoIcons class for iOS style icons.
@@ -63,6 +64,8 @@ dependencies:
 
   # Image picker untuk mengambil gambar dari kamera atau galeri
   image_picker: ^1.1.2
+  # File picker untuk memilih file dokumen
+  file_picker: ^9.2.1
   syncfusion_flutter_calendar: ^28.2.11
   syncfusion_localizations: ^28.2.11
   signature: ^6.0.0
@@ -81,6 +84,13 @@ dependencies:
   # Untuk fungsi hash
   crypto: ^3.0.3
 
+  # Package untuk generate PDF
+  pdf: ^3.10.8
+  # Package untuk menyimpan file
+  path_provider: ^2.1.2
+  # Package untuk membuka file
+  open_file: ^3.3.2
+
 dev_dependencies:
   flutter_test:
     sdk: flutter
@@ -124,6 +134,10 @@ flutter:
         - asset: assets/font/DMSans-VariableFont_opsz,wght.ttf
         - asset: assets/font/DMSans-Italic-VariableFont_opsz,wght.ttf
           style: italic
+        - asset: assets/font/DMSans-Regular.ttf
+          weight: 400
+        - asset: assets/font/DMSans-Bold.ttf
+          weight: 700
   #   - family: Trajan Pro
   #     fonts:
   #       - asset: fonts/TrajanPro.ttf
