Perbarui model LokasiPenyaluran dengan mengganti properti alamat menjadi alamatLengkap. Modifikasi tampilan dan controller di modul donatur dan petugas desa untuk menggunakan properti baru ini. Tambahkan fungsionalitas untuk mengelola lokasi penyaluran, termasuk penghapusan dan pengeditan lokasi. Perbarui rute aplikasi untuk menambahkan halaman lokasi penyaluran baru dan pastikan controller terdaftar dengan benar.

This commit is contained in:
Khafidh Fuadi
2025-03-30 20:05:22 +07:00
parent ba3e71efe7
commit 3f78514175
17 changed files with 1706 additions and 715 deletions

View File

View File

@ -2,27 +2,27 @@ C/C++ Structured LogO
M M
KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC
A A
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD> ?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  <08><>Ƹ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>
 
}D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\additional_project_files.txt  <08><><EFBFBD><EFBFBD><EFBFBD>2  <20><><EFBFBD><EFBFBD><EFBFBD>2~ }D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\additional_project_files.txt  <08><>Ƹ<EFBFBD>2  <20><><EFBFBD><EFBFBD><EFBFBD>2~
| |
zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\android_gradle_build.json  <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD> zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\android_gradle_build.json  <08><>Ƹ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>
<EFBFBD> <EFBFBD>
D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\android_gradle_build_mini.json  <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2p D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\android_gradle_build_mini.json  <08><>Ƹ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2p
n n
lD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build.ninja  <08><><EFBFBD><EFBFBD><EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2t lD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build.ninja  <08><>Ƹ<EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2t
r r
pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build.ninja.txt  <08><><EFBFBD><EFBFBD><EFBFBD>2y pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build.ninja.txt  <08><>Ƹ<EFBFBD>2y
w w
uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build_file_index.txt  <08><><EFBFBD><EFBFBD><EFBFBD>2 uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build_file_index.txt  <08><>Ƹ<EFBFBD>2
K <20><><EFBFBD><EFBFBD><EFBFBD>2z K <20><><EFBFBD><EFBFBD><EFBFBD>2z
x x
vD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\compile_commands.json  <08><>Ƹ<EFBFBD>2 ~ vD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\compile_commands.json  <08><>Ƹ<EFBFBD>2 ~
| |
zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\compile_commands.json.bin  <08><>Ƹ<EFBFBD>2 zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\compile_commands.json.bin  <08><>Ƹ<EFBFBD>2
<EFBFBD> <EFBFBD>
<EFBFBD> <EFBFBD>
<EFBFBD>D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\metadata_generation_command.txt  <08><>Ƹ<EFBFBD>2 <18> <20><><EFBFBD><EFBFBD><EFBFBD>2w <EFBFBD>D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\metadata_generation_command.txt  <08><>Ƹ<EFBFBD>2 <18> <20><><EFBFBD><EFBFBD><EFBFBD>2w
u u
sD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\prefab_config.json  <08><>Ƹ<EFBFBD>2 sD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\prefab_config.json  <08><>Ƹ<EFBFBD>2
 ( <20><><EFBFBD><EFBFBD><EFBFBD>2|  ( <20><><EFBFBD><EFBFBD><EFBFBD>2|

View File

@ -2,27 +2,27 @@ C/C++ Structured LogO
M M
KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC
A A
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD> ?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  ΁Ƹ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>
<EFBFBD> <EFBFBD>
D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\additional_project_files.txt  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2  <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD> D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\additional_project_files.txt  ΁Ƹ<EFBFBD>2  <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>
~ ~
|D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\android_gradle_build.json  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD> |D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\android_gradle_build.json  ΁Ƹ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>
<EFBFBD> <EFBFBD>
<EFBFBD>D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\android_gradle_build_mini.json  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2r <EFBFBD>D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\android_gradle_build_mini.json  ΁Ƹ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2r
p p
nD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2v nD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja  ΁Ƹ<EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2v
t t
rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja.txt  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2{ rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja.txt  ΁Ƹ<EFBFBD>2{
y y
wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build_file_index.txt  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2 wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build_file_index.txt  ΁Ƹ<EFBFBD>2
K <20><><EFBFBD><EFBFBD><EFBFBD>2| K <20><><EFBFBD><EFBFBD><EFBFBD>2|
z z
xD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\compile_commands.json  ΁Ƹ<CE81>2 <09> xD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\compile_commands.json  ΁Ƹ<CE81>2 <09>
~ ~
|D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\compile_commands.json.bin  ΁Ƹ<CE81>2 |D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\compile_commands.json.bin  ΁Ƹ<CE81>2
<EFBFBD> <EFBFBD>
<EFBFBD> <EFBFBD>
<EFBFBD>D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\metadata_generation_command.txt  ΁Ƹ<CE81>2 <18> <20><><EFBFBD><EFBFBD><EFBFBD>2y <EFBFBD>D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\metadata_generation_command.txt  ΁Ƹ<CE81>2 <18> <20><><EFBFBD><EFBFBD><EFBFBD>2y
w w
uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\prefab_config.json  ΁Ƹ<CE81>2 uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\prefab_config.json  ΁Ƹ<CE81>2
 ( <20><><EFBFBD><EFBFBD><EFBFBD>2~  ( <20><><EFBFBD><EFBFBD><EFBFBD>2~

View File

@ -2,27 +2,27 @@ C/C++ Structured LogO
M M
KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC
A A
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2{ ?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  <08><>Ƹ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2{
y y
wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\additional_project_files.txt  <08><><EFBFBD><EFBFBD><EFBFBD>2  <20><><EFBFBD><EFBFBD><EFBFBD>2x wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\additional_project_files.txt  <08><>Ƹ<EFBFBD>2  <20><><EFBFBD><EFBFBD><EFBFBD>2x
v v
tD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\android_gradle_build.json  <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2} tD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\android_gradle_build.json  <08><>Ƹ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2}
{ {
yD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\android_gradle_build_mini.json  <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2j yD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\android_gradle_build_mini.json  <08><>Ƹ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2j
h h
fD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build.ninja  <08><><EFBFBD><EFBFBD><EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2n fD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build.ninja  <08><>Ƹ<EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2n
l l
jD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build.ninja.txt  <08><><EFBFBD><EFBFBD><EFBFBD>2s jD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build.ninja.txt  <08><>Ƹ<EFBFBD>2s
q q
oD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build_file_index.txt  <08><><EFBFBD><EFBFBD><EFBFBD>2 oD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\build_file_index.txt  <08><>Ƹ<EFBFBD>2
K <20><><EFBFBD><EFBFBD><EFBFBD>2t K <20><><EFBFBD><EFBFBD><EFBFBD>2t
r r
pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\compile_commands.json  <08><>Ƹ<EFBFBD>2 x pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\compile_commands.json  <08><>Ƹ<EFBFBD>2 x
v v
tD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\compile_commands.json.bin  <08><>Ƹ<EFBFBD>2 tD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\compile_commands.json.bin  <08><>Ƹ<EFBFBD>2
~ ~
| |
zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\metadata_generation_command.txt  <08><>Ƹ<EFBFBD>2 <18> <20><><EFBFBD><EFBFBD><EFBFBD>2q zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\metadata_generation_command.txt  <08><>Ƹ<EFBFBD>2 <18> <20><><EFBFBD><EFBFBD><EFBFBD>2q
o o
mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\prefab_config.json  <08><>Ƹ<EFBFBD>2 mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\prefab_config.json  <08><>Ƹ<EFBFBD>2
 ( <20><><EFBFBD><EFBFBD><EFBFBD>2v  ( <20><><EFBFBD><EFBFBD><EFBFBD>2v

View File

@ -2,27 +2,27 @@ C/C++ Structured LogO
M M
KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC KC:\dev\flutter\packages\flutter_tools\gradle\src\main\groovy\CMakeLists.txtC
A A
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2~ ?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  ʃƸ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2~
| |
zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\additional_project_files.txt  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2  <20><><EFBFBD><EFBFBD><EFBFBD>2{ zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\additional_project_files.txt  ʃƸ<EFBFBD>2  <20><><EFBFBD><EFBFBD><EFBFBD>2{
y y
wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\android_gradle_build.json  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD> wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\android_gradle_build.json  ʃƸ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>
~ ~
|D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\android_gradle_build_mini.json  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2m |D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\android_gradle_build_mini.json  ʃƸ<EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2m
k k
iD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2q iD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja  ʃƸ<EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2q
o o
mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja.txt  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2v mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja.txt  ʃƸ<EFBFBD>2v
t t
rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build_file_index.txt  <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2 rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build_file_index.txt  ʃƸ<EFBFBD>2
K <20><><EFBFBD><EFBFBD><EFBFBD>2w K <20><><EFBFBD><EFBFBD><EFBFBD>2w
u u
sD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\compile_commands.json  ʃƸ<CA83>2 { sD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\compile_commands.json  ʃƸ<CA83>2 {
y y
wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\compile_commands.json.bin  ʃƸ<CA83>2 wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\compile_commands.json.bin  ʃƸ<CA83>2
<EFBFBD> <EFBFBD>
 
}D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\metadata_generation_command.txt  ʃƸ<CA83>2 <18> <20><><EFBFBD><EFBFBD><EFBFBD>2t }D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\metadata_generation_command.txt  ʃƸ<CA83>2 <18> <20><><EFBFBD><EFBFBD><EFBFBD>2t
r r
pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\prefab_config.json  ʃƸ<CA83>2 pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\prefab_config.json  ʃƸ<CA83>2
 ( <20><><EFBFBD><EFBFBD><EFBFBD>2y  ( <20><><EFBFBD><EFBFBD><EFBFBD>2y

View File

@ -3,7 +3,7 @@ import 'dart:convert';
class LokasiPenyaluranModel { class LokasiPenyaluranModel {
final String id; final String id;
final String nama; final String nama;
final String? alamat; final String? alamatLengkap;
final String? desa; final String? desa;
final String? kecamatan; final String? kecamatan;
final String? kabupaten; final String? kabupaten;
@ -19,7 +19,7 @@ class LokasiPenyaluranModel {
LokasiPenyaluranModel({ LokasiPenyaluranModel({
required this.id, required this.id,
required this.nama, required this.nama,
this.alamat, this.alamatLengkap,
this.desa, this.desa,
this.kecamatan, this.kecamatan,
this.kabupaten, this.kabupaten,
@ -42,7 +42,7 @@ class LokasiPenyaluranModel {
LokasiPenyaluranModel( LokasiPenyaluranModel(
id: json["id"], id: json["id"],
nama: json["nama"], nama: json["nama"],
alamat: json["alamat"], alamatLengkap: json["alamat_lengkap"],
desa: json["desa"], desa: json["desa"],
kecamatan: json["kecamatan"], kecamatan: json["kecamatan"],
kabupaten: json["kabupaten"], kabupaten: json["kabupaten"],
@ -61,7 +61,7 @@ class LokasiPenyaluranModel {
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"id": id, "id": id,
"nama": nama, "nama": nama,
"alamat": alamat, "alamat_lengkap": alamatLengkap,
"desa": desa, "desa": desa,
"kecamatan": kecamatan, "kecamatan": kecamatan,
"kabupaten": kabupaten, "kabupaten": kabupaten,

View File

@ -1196,7 +1196,7 @@ class _FormPenitipanBantuanState extends State<FormPenitipanBantuan> {
value: selectedLokasiPenyaluranId, value: selectedLokasiPenyaluranId,
items: controller.lokasiPenyaluran.map((lokasi) { items: controller.lokasiPenyaluran.map((lokasi) {
String alamatLengkap = [ String alamatLengkap = [
lokasi.alamat, lokasi.alamatLengkap,
lokasi.desa, lokasi.desa,
lokasi.kecamatan, lokasi.kecamatan,
lokasi.kabupaten, lokasi.kabupaten,

View File

@ -101,7 +101,8 @@ class DetailPenyaluranController extends GetxController {
// Ambil data penerima penyaluran // Ambil data penerima penyaluran
final penerimaPenyaluranData = await _supabaseService.client final penerimaPenyaluranData = await _supabaseService.client
.from('penerima_penyaluran') .from('penerima_penyaluran')
.select('*, warga:warga_id(*)') .select(
'*, warga:warga_id(*, desa:desa_id(*)), stok_bantuan:stok_bantuan_id(*)')
.eq('penyaluran_bantuan_id', penyaluranId); .eq('penyaluran_bantuan_id', penyaluranId);
final List<PenerimaPenyaluranModel> penerima = []; final List<PenerimaPenyaluranModel> penerima = [];

View File

@ -588,19 +588,21 @@ class JadwalPenyaluranController extends GetxController {
} }
Future<void> loadLokasiPenyaluranData() async { Future<void> loadLokasiPenyaluranData() async {
isLokasiLoading.value = true;
try { try {
isLokasiLoading(true); final data = await _supabaseService.getLokasiPenyaluran(
final lokasiData = await _supabaseService.getAllLokasiPenyaluran(); petugasId: user?.id,
if (lokasiData != null) { );
for (var lokasi in lokasiData) {
final lokasiModel = LokasiPenyaluranModel.fromJson(lokasi); // Bersihkan cache dan tambahkan data baru
lokasiPenyaluranCache[lokasiModel.id] = lokasiModel; lokasiPenyaluranCache.clear();
} for (final lokasi in data) {
lokasiPenyaluranCache[lokasi.id] = lokasi;
} }
} catch (e) { } catch (e) {
print('Error loading lokasi penyaluran data: $e'); print('Error loading lokasi penyaluran: $e');
} finally { } finally {
isLokasiLoading(false); isLokasiLoading.value = false;
} }
} }
@ -869,4 +871,92 @@ class JadwalPenyaluranController extends GetxController {
// Kembalikan representasi string dari hash // Kembalikan representasi string dari hash
return hash.toString(); return hash.toString();
} }
// Mengedit lokasi penyaluran
void editLokasiPenyaluran(String lokasiId) {
if (lokasiPenyaluranCache.containsKey(lokasiId)) {
// Ambil data lokasi yang akan diedit
final lokasi = lokasiPenyaluranCache[lokasiId];
// Navigasi ke halaman edit dengan membawa data lokasi
Get.toNamed('/petugas-desa/edit-lokasi-penyaluran', arguments: {
'lokasi_id': lokasiId,
'lokasi': lokasi,
});
} else {
Get.snackbar(
'Gagal',
'Data lokasi tidak ditemukan',
backgroundColor: Colors.red.shade100,
colorText: Colors.red.shade800,
snackPosition: SnackPosition.BOTTOM,
);
}
}
// Menghapus lokasi penyaluran
void hapusLokasiPenyaluran(String lokasiId) {
// Tampilkan dialog konfirmasi penghapusan
Get.dialog(
AlertDialog(
title: const Text('Konfirmasi Hapus'),
content: const Text('Apakah Anda yakin ingin menghapus lokasi ini?'),
actions: [
TextButton(
onPressed: () => Get.back(),
child: const Text('BATAL'),
),
TextButton(
onPressed: () async {
Get.back(); // Tutup dialog
// Tampilkan loading
Get.dialog(
const Center(
child: CircularProgressIndicator(),
),
barrierDismissible: false,
);
try {
// Lakukan penghapusan di database
await _supabaseService.deleteLokasiPenyaluran(lokasiId);
// Hapus data dari cache lokal
lokasiPenyaluranCache.remove(lokasiId);
// Tutup dialog loading
Get.back();
// Tampilkan notifikasi berhasil
Get.snackbar(
'Berhasil',
'Lokasi penyaluran berhasil dihapus',
backgroundColor: Colors.green.shade100,
colorText: Colors.green.shade800,
snackPosition: SnackPosition.BOTTOM,
);
} catch (e) {
// Tutup dialog loading
Get.back();
// Tampilkan pesan error
Get.snackbar(
'Gagal',
'Terjadi kesalahan: ${e.toString()}',
backgroundColor: Colors.red.shade100,
colorText: Colors.red.shade800,
snackPosition: SnackPosition.BOTTOM,
);
}
},
style: TextButton.styleFrom(
foregroundColor: Colors.red,
),
child: const Text('HAPUS'),
),
],
),
);
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,507 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/jadwal_penyaluran_controller.dart';
import 'package:penyaluran_app/app/theme/app_theme.dart';
import 'package:penyaluran_app/app/routes/app_pages.dart';
class LokasiPenyaluranView extends GetView<JadwalPenyaluranController> {
const LokasiPenyaluranView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Lokasi Penyaluran'),
backgroundColor: AppTheme.primaryColor,
foregroundColor: Colors.white,
),
body: _buildLokasiPenyaluranList(),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => Get.toNamed(Routes.tambahLokasiPenyaluran),
backgroundColor: AppTheme.primaryColor,
icon: const Icon(Icons.add_location, color: Colors.white),
label:
const Text('Tambah Lokasi', style: TextStyle(color: Colors.white)),
),
);
}
Widget _buildLokasiPenyaluranList() {
return RefreshIndicator(
onRefresh: () => controller.loadLokasiPenyaluranData(),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header dengan gradient yang lebih menarik
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.blue.shade700,
Colors.blue.shade500,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.blue.shade200.withOpacity(0.5),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.location_on,
color: Colors.white.withOpacity(0.9),
size: 24,
),
const SizedBox(width: 10),
Text(
'Daftar Lokasi Penyaluran',
style: Theme.of(Get.context!)
.textTheme
.titleLarge
?.copyWith(
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
const SizedBox(height: 10),
Text(
'Kelola lokasi penyaluran bantuan untuk masyarakat dengan lebih mudah',
style: TextStyle(
fontSize: 14,
color: Colors.white.withOpacity(0.9),
),
),
const SizedBox(height: 16),
// Counter jumlah lokasi
Container(
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(30),
),
child: Obx(() => Text(
'${controller.lokasiPenyaluranCache.length} Lokasi Terdaftar',
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 12,
),
)),
),
],
),
),
const SizedBox(height: 20),
// Daftar Lokasi
Expanded(
child: Obx(() {
if (controller.isLokasiLoading.value) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (controller.lokasiPenyaluranCache.isEmpty) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.grey.shade100,
shape: BoxShape.circle,
),
child: Icon(
Icons.location_off,
size: 64,
color: Colors.grey.shade400,
),
),
const SizedBox(height: 16),
Text(
'Belum ada lokasi penyaluran',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey.shade600,
),
),
const SizedBox(height: 8),
Text(
'Tambahkan lokasi penyaluran untuk memulai',
style: TextStyle(
fontSize: 14,
color: Colors.grey.shade500,
),
),
const SizedBox(height: 20),
ElevatedButton.icon(
onPressed: () =>
Get.toNamed(Routes.tambahLokasiPenyaluran),
icon: const Icon(Icons.add_location),
label: const Text('Tambah Lokasi'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.shade600,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
),
),
],
),
);
}
return ListView.builder(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(top: 8, bottom: 100),
itemCount: controller.lokasiPenyaluranCache.length +
1, // +1 untuk footer
itemBuilder: (context, index) {
// Footer item
if (index == controller.lokasiPenyaluranCache.length) {
return Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Text(
'Tidak ada lokasi lainnya',
style: TextStyle(
fontSize: 13,
color: Colors.grey.shade500,
fontStyle: FontStyle.italic,
),
),
),
);
}
// Item lokasi normal
final lokasi = controller.lokasiPenyaluranCache.values
.elementAt(index);
final lokasiId =
controller.lokasiPenyaluranCache.keys.elementAt(index);
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Card(
margin: EdgeInsets.zero,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: InkWell(
borderRadius: BorderRadius.circular(16),
onTap: () {
// Tambahkan aksi ketika card diklik
},
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Icon Lokasi dengan latar belakang
Hero(
tag: 'lokasi_icon_$lokasiId',
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue.shade50,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color:
Colors.blue.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Icon(
Icons.location_on,
color: Colors.blue.shade700,
size: 28,
),
),
),
const SizedBox(width: 16),
// Informasi utama lokasi
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Hero(
tag: 'lokasi_nama_$lokasiId',
child: Material(
color: Colors.transparent,
child: Text(
lokasi.nama,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
),
),
const SizedBox(height: 4),
if (lokasi.alamatLengkap != null &&
lokasi.alamatLengkap!.isNotEmpty)
Text(
lokasi.alamatLengkap!,
style: TextStyle(
fontSize: 14,
color: Colors.grey.shade700,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
// Indikator koordinat tersedia
if (lokasi.latitude != null &&
lokasi.longitude != null)
Padding(
padding: const EdgeInsets.only(
top: 4.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.gps_fixed,
size: 14,
color: Colors.blue.shade500,
),
const SizedBox(width: 4),
Text(
'Koordinat tersedia',
style: TextStyle(
fontSize: 12,
color:
Colors.blue.shade500,
fontWeight:
FontWeight.w500,
),
),
],
),
),
],
),
),
// Badge "NEW" jika lokasi baru dibuat (kurang dari 3 hari)
if (_isNewLocation(lokasi.createdAt))
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: Colors.orange.shade500,
borderRadius:
BorderRadius.circular(12),
),
child: const Text(
'BARU',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 10,
),
),
),
],
),
// Divider dan tag kategori
if (lokasi.isLokasiTitip ||
(lokasi.desa != null &&
lokasi.desa!.isNotEmpty))
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Divider(color: Colors.grey.shade200),
),
// Informasi tambahan dan tag
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Wrap(
spacing: 8,
runSpacing: 8,
children: [
// Tag lokasi penitipan jika ada
if (lokasi.isLokasiTitip)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
decoration: BoxDecoration(
color: Colors.green.shade100,
borderRadius:
BorderRadius.circular(30),
border: Border.all(
color: Colors.green.shade300),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.check_circle_outline,
size: 16,
color: Colors.green.shade800,
),
const SizedBox(width: 4),
Text(
'Lokasi Penitipan',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.green.shade800,
),
),
],
),
),
// Tag informasi desa jika ada
if (lokasi.desa != null &&
lokasi.desa!.isNotEmpty)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius:
BorderRadius.circular(30),
border: Border.all(
color: Colors.blue.shade200),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.location_city,
size: 16,
color: Colors.blue.shade800,
),
const SizedBox(width: 4),
Text(
lokasi.desa!,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.blue.shade800,
),
),
],
),
),
],
),
),
// Tombol aksi
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// Tombol Hapus
Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
// Aksi hapus lokasi
controller.hapusLokasiPenyaluran(
lokasiId);
},
borderRadius:
BorderRadius.circular(30),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0, vertical: 4.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.delete_outline,
color: Colors.red.shade600,
size: 18),
const SizedBox(width: 4),
Text(
'Hapus',
style: TextStyle(
color: Colors.red.shade600,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
),
],
),
),
],
),
),
),
),
);
},
);
}),
),
],
),
),
);
}
// Helper method untuk menentukan apakah lokasi baru dibuat (kurang dari 3 hari)
bool _isNewLocation(DateTime createdAt) {
final now = DateTime.now();
final difference = now.difference(createdAt);
return difference.inDays < 3;
}
}

View File

@ -5,12 +5,16 @@ import 'package:penyaluran_app/app/theme/app_theme.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/components/jadwal_section_widget.dart'; import 'package:penyaluran_app/app/modules/petugas_desa/components/jadwal_section_widget.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/components/calendar_view_widget.dart'; import 'package:penyaluran_app/app/modules/petugas_desa/components/calendar_view_widget.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/tambah_penyaluran_view.dart'; import 'package:penyaluran_app/app/modules/petugas_desa/views/tambah_penyaluran_view.dart';
import 'package:penyaluran_app/app/routes/app_pages.dart';
class PenyaluranView extends GetView<JadwalPenyaluranController> { class PenyaluranView extends GetView<JadwalPenyaluranController> {
const PenyaluranView({super.key}); const PenyaluranView({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Memastikan controller tersedia
if (!Get.isRegistered<JadwalPenyaluranController>()) {
Get.put(JadwalPenyaluranController());
}
return DefaultTabController( return DefaultTabController(
length: 2, length: 2,
child: Scaffold( child: Scaffold(
@ -84,11 +88,6 @@ class PenyaluranView extends GetView<JadwalPenyaluranController> {
// Ringkasan jadwal // Ringkasan jadwal
_buildJadwalSummary(Get.context!), _buildJadwalSummary(Get.context!),
const SizedBox(height: 16),
// Tombol untuk mengelola lokasi penyaluran
_buildLokasiPenyaluranSection(),
const SizedBox(height: 24), const SizedBox(height: 24),
// Jadwal hari ini // Jadwal hari ini
@ -237,240 +236,4 @@ class PenyaluranView extends GetView<JadwalPenyaluranController> {
], ],
); );
} }
// Widget untuk menampilkan section lokasi penyaluran
Widget _buildLokasiPenyaluranSection() {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(color: Colors.blue.shade100, width: 1),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Lokasi Penyaluran',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.blue.shade800,
),
),
OutlinedButton.icon(
onPressed: () {
// Menampilkan dialog daftar lokasi penyaluran
_showLokasiPenyaluranDialog();
},
icon: const Icon(Icons.map, size: 16),
label: const Text('Lihat Lokasi'),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.blue,
side: BorderSide(color: Colors.blue.shade300),
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
),
),
],
),
const SizedBox(height: 8),
Text(
'Kelola lokasi penyaluran bantuan untuk masyarakat dengan lebih mudah',
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade600,
),
),
const SizedBox(height: 12),
ElevatedButton.icon(
onPressed: () => Get.toNamed(Routes.tambahLokasiPenyaluran),
icon: const Icon(Icons.add_location, size: 16),
label: const Text('Tambah Lokasi Penyaluran Baru'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.shade50,
foregroundColor: Colors.blue.shade700,
padding:
const EdgeInsets.symmetric(vertical: 10, horizontal: 12),
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: BorderSide(color: Colors.blue.shade200),
),
),
),
],
),
),
);
}
// Fungsi untuk menampilkan dialog daftar lokasi penyaluran
void _showLokasiPenyaluranDialog() {
Get.dialog(
Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Daftar Lokasi Penyaluran',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.blue.shade800,
),
),
IconButton(
onPressed: () => Get.back(),
icon: const Icon(Icons.close),
visualDensity: VisualDensity.compact,
),
],
),
const SizedBox(height: 12),
Container(
constraints: BoxConstraints(
maxHeight: Get.height * 0.5,
),
width: double.infinity,
child: Obx(() {
if (controller.isLokasiLoading.value) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (controller.lokasiPenyaluranCache.isEmpty) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.location_off,
size: 48,
color: Colors.grey.shade400,
),
const SizedBox(height: 16),
Text(
'Belum ada lokasi penyaluran',
style: TextStyle(
color: Colors.grey.shade600,
),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: () {
Get.back();
Get.toNamed(Routes.tambahLokasiPenyaluran);
},
icon: const Icon(Icons.add_location),
label: const Text('Tambah Lokasi'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
),
],
),
);
}
return ListView.builder(
shrinkWrap: true,
itemCount: controller.lokasiPenyaluranCache.length,
itemBuilder: (context, index) {
final lokasi = controller.lokasiPenyaluranCache.values
.elementAt(index);
final lokasiId = controller.lokasiPenyaluranCache.keys
.elementAt(index);
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: ListTile(
title: Text(
lokasi.nama,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (lokasi.alamat != null &&
lokasi.alamat!.isNotEmpty)
Text(lokasi.alamat!),
Row(
children: [
if (lokasi.isLokasiTitip)
Container(
margin: const EdgeInsets.only(top: 4),
padding: const EdgeInsets.symmetric(
horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.green.shade100,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'Lokasi Penitipan',
style: TextStyle(
fontSize: 10,
color: Colors.green.shade800,
),
),
),
],
),
],
),
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue.shade50,
shape: BoxShape.circle,
),
child: Icon(
Icons.location_on,
color: Colors.blue.shade700,
),
),
),
);
},
);
}),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
OutlinedButton(
onPressed: () {
Get.back();
Get.toNamed(Routes.tambahLokasiPenyaluran);
},
child: const Text('Tambah Lokasi Baru'),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.blue,
),
),
],
),
],
),
),
),
);
}
} }

View File

@ -386,6 +386,15 @@ class PetugasDesaView extends GetView<PetugasDesaController> {
Get.toNamed('/daftar-donatur'); Get.toNamed('/daftar-donatur');
}, },
), ),
_buildMenuItem(
icon: Icons.location_on_outlined,
activeIcon: Icons.location_on,
title: 'Lokasi Penyaluran',
onTap: () {
Navigator.pop(context);
Get.toNamed('/lokasi-penyaluran');
},
),
_buildMenuItem( _buildMenuItem(
icon: Icons.description_outlined, icon: Icons.description_outlined,
activeIcon: Icons.description, activeIcon: Icons.description,

View File

@ -15,16 +15,28 @@ class TambahLokasiPenyaluranView extends GetView<JadwalPenyaluranController> {
backgroundColor: AppTheme.primaryColor, backgroundColor: AppTheme.primaryColor,
foregroundColor: Colors.white, foregroundColor: Colors.white,
), ),
body: _buildTambahLokasiPenyaluranForm(context), body: _LokasiPenyaluranForm(controller: controller),
); );
} }
}
Widget _buildTambahLokasiPenyaluranForm(BuildContext context) { class _LokasiPenyaluranForm extends StatefulWidget {
final formKey = GlobalKey<FormState>(); final JadwalPenyaluranController controller;
final TextEditingController namaController = TextEditingController();
final TextEditingController alamatLengkapController =
TextEditingController();
const _LokasiPenyaluranForm({required this.controller});
@override
State<_LokasiPenyaluranForm> createState() => _LokasiPenyaluranFormState();
}
class _LokasiPenyaluranFormState extends State<_LokasiPenyaluranForm> {
final formKey = GlobalKey<FormState>();
final TextEditingController namaController = TextEditingController();
final TextEditingController alamatLengkapController = TextEditingController();
bool isLokasiTitip = false;
@override
Widget build(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Form( child: Form(
@ -95,6 +107,29 @@ class TambahLokasiPenyaluranView extends GetView<JadwalPenyaluranController> {
return null; return null;
}, },
), ),
const SizedBox(height: 16),
// Checkbox Is Lokasi Titip
Row(
children: [
Checkbox(
value: isLokasiTitip,
activeColor: AppTheme.primaryColor,
onChanged: (newValue) {
setState(() {
isLokasiTitip = newValue ?? false;
});
},
),
const Text('Lokasi Titip'),
const SizedBox(width: 4),
const Tooltip(
message:
'Centang jika lokasi ini merupakan lokasi yang dapat menerima penitipan',
child: Icon(Icons.info_outline, size: 16),
),
],
),
const SizedBox(height: 24), const SizedBox(height: 24),
// Tombol Submit // Tombol Submit
@ -107,6 +142,7 @@ class TambahLokasiPenyaluranView extends GetView<JadwalPenyaluranController> {
_tambahLokasiPenyaluran( _tambahLokasiPenyaluran(
nama: namaController.text, nama: namaController.text,
alamatLengkap: alamatLengkapController.text, alamatLengkap: alamatLengkapController.text,
isLokasiTitip: isLokasiTitip,
); );
} }
}, },
@ -137,6 +173,7 @@ class TambahLokasiPenyaluranView extends GetView<JadwalPenyaluranController> {
Future<void> _tambahLokasiPenyaluran({ Future<void> _tambahLokasiPenyaluran({
required String nama, required String nama,
required String alamatLengkap, required String alamatLengkap,
required bool isLokasiTitip,
}) async { }) async {
try { try {
// Tampilkan loading // Tampilkan loading
@ -152,7 +189,8 @@ class TambahLokasiPenyaluranView extends GetView<JadwalPenyaluranController> {
final String id = uuid.v4(); final String id = uuid.v4();
// Ambil ID petugas desa yang sedang login dari controller // Ambil ID petugas desa yang sedang login dari controller
final String? petugasDesaId = controller.supabaseService.currentUser?.id; final String? petugasDesaId =
widget.controller.supabaseService.currentUser?.id;
if (petugasDesaId == null) { if (petugasDesaId == null) {
Get.back(); // Tutup dialog loading Get.back(); // Tutup dialog loading
@ -167,7 +205,7 @@ class TambahLokasiPenyaluranView extends GetView<JadwalPenyaluranController> {
// Dapatkan desa_id dari data petugas desa // Dapatkan desa_id dari data petugas desa
// Ambil data petugas desa dari Supabase untuk mendapatkan desa_id // Ambil data petugas desa dari Supabase untuk mendapatkan desa_id
final petugasDesaData = await controller.supabaseService.client final petugasDesaData = await widget.controller.supabaseService.client
.from('petugas_desa') .from('petugas_desa')
.select('desa_id') .select('desa_id')
.eq('id', petugasDesaId) .eq('id', petugasDesaId)
@ -193,11 +231,12 @@ class TambahLokasiPenyaluranView extends GetView<JadwalPenyaluranController> {
'nama': nama, 'nama': nama,
'alamat_lengkap': alamatLengkap, 'alamat_lengkap': alamatLengkap,
'desa_id': desaId, 'desa_id': desaId,
'is_lokasi_titip': isLokasiTitip,
'created_at': DateTime.now().toIso8601String(), 'created_at': DateTime.now().toIso8601String(),
}; };
// Insert data ke tabel lokasi_penyaluran // Insert data ke tabel lokasi_penyaluran
await controller.supabaseService.client await widget.controller.supabaseService.client
.from('lokasi_penyaluran') .from('lokasi_penyaluran')
.insert(data); .insert(data);
@ -216,7 +255,7 @@ class TambahLokasiPenyaluranView extends GetView<JadwalPenyaluranController> {
Get.back(); Get.back();
// Refresh data di controller // Refresh data di controller
controller.refreshData(); widget.controller.refreshData();
} catch (e) { } catch (e) {
// Tutup dialog loading // Tutup dialog loading
Get.back(); Get.back();

View File

@ -13,6 +13,7 @@ import 'package:penyaluran_app/app/modules/petugas_desa/views/daftar_donatur_vie
import 'package:penyaluran_app/app/modules/petugas_desa/views/detail_donatur_view.dart'; import 'package:penyaluran_app/app/modules/petugas_desa/views/detail_donatur_view.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/tambah_penyaluran_view.dart'; import 'package:penyaluran_app/app/modules/petugas_desa/views/tambah_penyaluran_view.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/tambah_lokasi_penyaluran_view.dart'; import 'package:penyaluran_app/app/modules/petugas_desa/views/tambah_lokasi_penyaluran_view.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/lokasi_penyaluran_view.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/riwayat_penyaluran_view.dart'; import 'package:penyaluran_app/app/modules/petugas_desa/views/riwayat_penyaluran_view.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/views/detail_penyaluran_page.dart'; import 'package:penyaluran_app/app/modules/petugas_desa/views/detail_penyaluran_page.dart';
import 'package:penyaluran_app/app/modules/petugas_desa/bindings/penyaluran_binding.dart'; import 'package:penyaluran_app/app/modules/petugas_desa/bindings/penyaluran_binding.dart';
@ -155,6 +156,11 @@ class AppPages {
page: () => const TambahLokasiPenyaluranView(), page: () => const TambahLokasiPenyaluranView(),
binding: PetugasDesaBinding(), binding: PetugasDesaBinding(),
), ),
GetPage(
name: _Paths.lokasiPenyaluran,
page: () => const LokasiPenyaluranView(),
binding: PetugasDesaBinding(),
),
GetPage( GetPage(
name: _Paths.detailPenyaluran, name: _Paths.detailPenyaluran,
page: () => DetailPenyaluranPage(), page: () => DetailPenyaluranPage(),

View File

@ -30,6 +30,7 @@ abstract class Routes {
static const detailDonatur = _Paths.detailDonatur; static const detailDonatur = _Paths.detailDonatur;
static const tambahPenyaluran = _Paths.tambahPenyaluran; static const tambahPenyaluran = _Paths.tambahPenyaluran;
static const tambahLokasiPenyaluran = _Paths.tambahLokasiPenyaluran; static const tambahLokasiPenyaluran = _Paths.tambahLokasiPenyaluran;
static const lokasiPenyaluran = _Paths.lokasiPenyaluran;
static const daftarPenerimaPenyaluran = _Paths.daftarPenerimaPenyaluran; static const daftarPenerimaPenyaluran = _Paths.daftarPenerimaPenyaluran;
static const detailPenerimaPenyaluran = _Paths.detailPenerimaPenyaluran; static const detailPenerimaPenyaluran = _Paths.detailPenerimaPenyaluran;
static const laporanPenyaluran = _Paths.laporanPenyaluran; static const laporanPenyaluran = _Paths.laporanPenyaluran;
@ -78,6 +79,7 @@ abstract class _Paths {
static const detailDonatur = '/daftar-donatur/detail'; static const detailDonatur = '/daftar-donatur/detail';
static const tambahPenyaluran = '/tambah-penyaluran'; static const tambahPenyaluran = '/tambah-penyaluran';
static const tambahLokasiPenyaluran = '/tambah-lokasi-penyaluran'; static const tambahLokasiPenyaluran = '/tambah-lokasi-penyaluran';
static const lokasiPenyaluran = '/lokasi-penyaluran';
static const daftarPenerimaPenyaluran = '/daftar-penerima-penyaluran'; static const daftarPenerimaPenyaluran = '/daftar-penerima-penyaluran';
static const detailPenerimaPenyaluran = '/detail-penerima-penyaluran'; static const detailPenerimaPenyaluran = '/detail-penerima-penyaluran';
static const laporanPenyaluran = '/laporan-penyaluran'; static const laporanPenyaluran = '/laporan-penyaluran';

View File

@ -3,6 +3,7 @@ import 'package:penyaluran_app/app/data/models/donatur_model.dart';
import 'package:penyaluran_app/app/data/models/petugas_desa_model.dart'; import 'package:penyaluran_app/app/data/models/petugas_desa_model.dart';
import 'package:penyaluran_app/app/data/models/user_model.dart'; import 'package:penyaluran_app/app/data/models/user_model.dart';
import 'package:penyaluran_app/app/data/models/warga_model.dart'; import 'package:penyaluran_app/app/data/models/warga_model.dart';
import 'package:penyaluran_app/app/data/models/lokasi_penyaluran_model.dart';
import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:supabase_flutter/supabase_flutter.dart';
import 'dart:io'; import 'dart:io';
@ -1736,6 +1737,33 @@ class SupabaseService extends GetxService {
} }
} }
// Metode untuk mendapatkan lokasi penyaluran berdasarkan ID petugas
Future<List<LokasiPenyaluranModel>> getLokasiPenyaluran(
{String? petugasId}) async {
try {
var query = client.from('lokasi_penyaluran').select('*');
final response = await query.order('nama');
return response
.map((data) => LokasiPenyaluranModel.fromJson(data))
.toList();
} catch (e) {
print('Error getting lokasi penyaluran: $e');
return [];
}
}
// Metode untuk menghapus lokasi penyaluran
Future<void> deleteLokasiPenyaluran(String lokasiId) async {
try {
await client.from('lokasi_penyaluran').delete().eq('id', lokasiId);
} catch (e) {
print('Error deleting lokasi penyaluran: $e');
throw e.toString();
}
}
// Metode untuk mendapatkan daftar penerima penyaluran berdasarkan ID penyaluran // Metode untuk mendapatkan daftar penerima penyaluran berdasarkan ID penyaluran
Future<List<Map<String, dynamic>>?> getPenerimaPenyaluran( Future<List<Map<String, dynamic>>?> getPenerimaPenyaluran(
String penyaluranId) async { String penyaluranId) async {