Perbarui beberapa file konfigurasi fingerprint untuk arsitektur arm64-v8a, armeabi-v7a, x86, dan x86_64. Modifikasi model SkemaBantuan untuk menggunakan operator null-aware pada jumlah diterima per orang. Perbarui logika pengambilan data di AuthProvider untuk menyederhanakan pengecekan dan logging. Tambahkan fungsionalitas baru di DonaturDashboardController untuk mengunggah foto bantuan dan memperbarui data yang disimpan. Hapus tampilan yang tidak digunakan di DonaturRiwayatPenitipanView dan perbarui tampilan di beberapa view untuk meningkatkan pengalaman pengguna.
This commit is contained in:
@ -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 <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>
|
||||
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint <08><><EFBFBD><EFBFBD><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><EFBFBD><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><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<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><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2p
|
||||
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><EFBFBD><EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2t
|
||||
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><EFBFBD><EFBFBD>2y
|
||||
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><EFBFBD><EFBFBD>2
|
||||
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><EFBFBD><EFBFBD>2 ~
|
||||
|
|
||||
|
|
||||
zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\compile_commands.json.bin <08><><EFBFBD><EFBFBD><EFBFBD>2
|
||||
<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><EFBFBD><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><EFBFBD><EFBFBD>2
|
||||
( <20><><EFBFBD><EFBFBD><EFBFBD>2|
|
||||
( <20><><EFBFBD><EFBFBD><EFBFBD>2|
|
@ -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 <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>
|
||||
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>
|
||||
<EFBFBD>
|
||||
D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\additional_project_files.txt <08><><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 <08><><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\android_gradle_build.json <08><><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 <08><><EFBFBD><EFBFBD><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\android_gradle_build_mini.json <08><><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 <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2r
|
||||
p
|
||||
nD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja <08><><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 <08><><EFBFBD><EFBFBD><EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2v
|
||||
t
|
||||
rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja.txt <08><><EFBFBD><EFBFBD><EFBFBD>2{
|
||||
rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build.ninja.txt <08><><EFBFBD><EFBFBD><EFBFBD>2{
|
||||
y
|
||||
wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build_file_index.txt <08><><EFBFBD><EFBFBD><EFBFBD>2
|
||||
wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\build_file_index.txt <08><><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 <08><><EFBFBD><EFBFBD><EFBFBD>2 <09>
|
||||
~
|
||||
~
|
||||
|D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\compile_commands.json.bin <08><><EFBFBD><EFBFBD><EFBFBD>2
|
||||
<EFBFBD>
|
||||
<EFBFBD>
|
||||
<EFBFBD>
|
||||
<EFBFBD>D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\armeabi-v7a\metadata_generation_command.txt <08><><EFBFBD><EFBFBD><EFBFBD>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 <08><><EFBFBD><EFBFBD><EFBFBD>2
|
||||
( <20><><EFBFBD><EFBFBD><EFBFBD>2~
|
||||
( <20><><EFBFBD><EFBFBD><EFBFBD>2~
|
@ -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 <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2{
|
||||
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint <08><><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2{
|
||||
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><EFBFBD><EFBFBD>2 <20><><EFBFBD><EFBFBD><EFBFBD>2x
|
||||
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><EFBFBD><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><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2j
|
||||
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><EFBFBD><EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2n
|
||||
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><EFBFBD><EFBFBD>2s
|
||||
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><EFBFBD><EFBFBD>2
|
||||
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><EFBFBD><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><EFBFBD><EFBFBD>2
|
||||
~
|
||||
|
|
||||
|
|
||||
zD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86\metadata_generation_command.txt <08><><EFBFBD><EFBFBD><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><EFBFBD><EFBFBD>2
|
||||
( <20><><EFBFBD><EFBFBD><EFBFBD>2v
|
||||
( <20><><EFBFBD><EFBFBD><EFBFBD>2v
|
@ -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 ِ<EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2~
|
||||
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint <EFBFBD><EFBFBD><EFBFBD><EFBFBD><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>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><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2 <20><><EFBFBD><EFBFBD><EFBFBD>2{
|
||||
y
|
||||
wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\android_gradle_build.json ِ<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><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\x86_64\android_gradle_build_mini.json ِ<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><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2m
|
||||
k
|
||||
iD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja ِ<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><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<18><> <20><><EFBFBD><EFBFBD><EFBFBD>2q
|
||||
o
|
||||
mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja.txt ِ<EFBFBD><EFBFBD><EFBFBD>2v
|
||||
mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja.txt <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2v
|
||||
t
|
||||
rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build_file_index.txt ِ<EFBFBD><EFBFBD><EFBFBD>2
|
||||
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
|
||||
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 <08><><EFBFBD><EFBFBD><EFBFBD>2 {
|
||||
y
|
||||
y
|
||||
wD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\compile_commands.json.bin <08><><EFBFBD><EFBFBD><EFBFBD>2
|
||||
<EFBFBD>
|
||||
|
||||
|
||||
}D:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\metadata_generation_command.txt <08><><EFBFBD><EFBFBD><EFBFBD>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 <08><><EFBFBD><EFBFBD><EFBFBD>2
|
||||
( <20><><EFBFBD><EFBFBD><EFBFBD>2y
|
||||
( <20><><EFBFBD><EFBFBD><EFBFBD>2y
|
@ -48,9 +48,7 @@ class SkemaBantuanModel {
|
||||
: null,
|
||||
stokBantuanId: json["stok_bantuan_id"],
|
||||
kategoriBantuanId: json["kategori_bantuan_id"],
|
||||
jumlahDiterimaPerOrang: json["jumlah_diterima_per_orang"] != null
|
||||
? json["jumlah_diterima_per_orang"].toDouble()
|
||||
: null,
|
||||
jumlahDiterimaPerOrang: json["jumlah_diterima_per_orang"]?.toDouble(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
|
@ -89,19 +89,14 @@ class AuthProvider {
|
||||
.eq('id', userId)
|
||||
.single();
|
||||
|
||||
if (profileResponse != null) {
|
||||
// Ekstrak data desa jika ada
|
||||
if (profileResponse['desa'] != null) {
|
||||
desa = DesaModel.fromJson(profileResponse['desa']);
|
||||
print('Data Desa: ${desa.nama}');
|
||||
}
|
||||
|
||||
roleData = WargaModel.fromJson(profileResponse);
|
||||
print('Data Warga: ${roleData.namaLengkap}');
|
||||
} else {
|
||||
print('Tidak menemukan data warga untuk ID: $userId');
|
||||
return null;
|
||||
// Ekstrak data desa jika ada
|
||||
if (profileResponse['desa'] != null) {
|
||||
desa = DesaModel.fromJson(profileResponse['desa']);
|
||||
print('Data Desa: ${desa.nama}');
|
||||
}
|
||||
|
||||
roleData = WargaModel.fromJson(profileResponse);
|
||||
print('Data Warga: ${roleData.namaLengkap}');
|
||||
} else if (roleName == 'petugas_desa') {
|
||||
profileResponse = await _supabaseService.client
|
||||
.from('petugas_desa')
|
||||
@ -109,17 +104,15 @@ class AuthProvider {
|
||||
.eq('id', userId)
|
||||
.single();
|
||||
|
||||
if (profileResponse != null) {
|
||||
// Ekstrak data desa jika ada
|
||||
if (profileResponse['desa'] != null) {
|
||||
desa = DesaModel.fromJson(profileResponse['desa']);
|
||||
print('Data Desa: ${desa.nama}');
|
||||
}
|
||||
|
||||
roleData = PetugasDesaModel.fromJson(profileResponse);
|
||||
print(
|
||||
'Data Petugas Desa: ${roleData.namaLengkap}, Desa: ${roleData.desa?.nama}');
|
||||
// Ekstrak data desa jika ada
|
||||
if (profileResponse['desa'] != null) {
|
||||
desa = DesaModel.fromJson(profileResponse['desa']);
|
||||
print('Data Desa: ${desa.nama}');
|
||||
}
|
||||
|
||||
roleData = PetugasDesaModel.fromJson(profileResponse);
|
||||
print(
|
||||
'Data Petugas Desa: ${roleData.namaLengkap}, Desa: ${roleData.desa?.nama}');
|
||||
} else if (roleName == 'donatur') {
|
||||
profileResponse = await _supabaseService.client
|
||||
.from('donatur')
|
||||
@ -252,19 +245,14 @@ class AuthProvider {
|
||||
.eq('id', userId)
|
||||
.single();
|
||||
|
||||
if (profileResponse != null) {
|
||||
// Ekstrak data desa jika ada
|
||||
if (profileResponse['desa'] != null) {
|
||||
desa = DesaModel.fromJson(profileResponse['desa']);
|
||||
print('Data Desa: ${desa.nama}');
|
||||
}
|
||||
|
||||
roleData = WargaModel.fromJson(profileResponse);
|
||||
print('Data Warga: ${roleData.namaLengkap}');
|
||||
} else {
|
||||
print('Tidak menemukan data warga untuk ID: $userId');
|
||||
return null;
|
||||
// Ekstrak data desa jika ada
|
||||
if (profileResponse['desa'] != null) {
|
||||
desa = DesaModel.fromJson(profileResponse['desa']);
|
||||
print('Data Desa: ${desa.nama}');
|
||||
}
|
||||
|
||||
roleData = WargaModel.fromJson(profileResponse);
|
||||
print('Data Warga: ${roleData.namaLengkap}');
|
||||
} else if (roleName.toLowerCase() == 'petugas_desa') {
|
||||
profileResponse = await _supabaseService.client
|
||||
.from('petugas_desa')
|
||||
@ -273,15 +261,13 @@ class AuthProvider {
|
||||
.eq('id', userId)
|
||||
.single();
|
||||
|
||||
if (profileResponse != null) {
|
||||
// Ekstrak data desa jika ada
|
||||
if (profileResponse['desa'] != null) {
|
||||
desa = DesaModel.fromJson(profileResponse['desa']);
|
||||
print('Data Desa: ${desa.nama}');
|
||||
}
|
||||
|
||||
roleData = PetugasDesaModel.fromJson(profileResponse);
|
||||
// Ekstrak data desa jika ada
|
||||
if (profileResponse['desa'] != null) {
|
||||
desa = DesaModel.fromJson(profileResponse['desa']);
|
||||
print('Data Desa: ${desa.nama}');
|
||||
}
|
||||
|
||||
roleData = PetugasDesaModel.fromJson(profileResponse);
|
||||
} else if (roleName.toLowerCase() == 'donatur') {
|
||||
profileResponse = await _supabaseService.client
|
||||
.from('donatur')
|
||||
@ -289,9 +275,7 @@ class AuthProvider {
|
||||
.eq('id', userId)
|
||||
.single();
|
||||
|
||||
if (profileResponse != null) {
|
||||
roleData = DonaturModel.fromJson(profileResponse);
|
||||
}
|
||||
roleData = DonaturModel.fromJson(profileResponse);
|
||||
}
|
||||
|
||||
if (roleData == null) {
|
||||
|
@ -401,9 +401,19 @@ class DonaturDashboardController extends GetxController {
|
||||
throw Exception('Foto bantuan harus diunggah');
|
||||
}
|
||||
|
||||
// Dapatkan informasi stok bantuan untuk mendapatkan nilai is_uang
|
||||
final selectedStokBantuan = stokBantuan.firstWhere(
|
||||
(stok) => stok.id == stokBantuanId,
|
||||
orElse: () => StokBantuanModel(),
|
||||
);
|
||||
|
||||
// Unggah foto bantuan ke storage menggunakan metode dari SupabaseService
|
||||
final fotoBantuanUrls = await _supabaseService.uploadMultipleFiles(
|
||||
fotoBantuanPaths, 'penitipan', 'foto_bantuan');
|
||||
fotoBantuanPaths, 'bantuan', 'foto_bantuan');
|
||||
|
||||
if (fotoBantuanUrls == null || fotoBantuanUrls.isEmpty) {
|
||||
throw 'Gagal mengupload foto bantuan';
|
||||
}
|
||||
|
||||
// Data yang akan disimpan
|
||||
final Map<String, dynamic> data = {
|
||||
@ -414,6 +424,7 @@ class DonaturDashboardController extends GetxController {
|
||||
'status': 'MENUNGGU',
|
||||
'tanggal_penitipan': DateTime.now().toIso8601String(),
|
||||
'foto_bantuan': fotoBantuanUrls,
|
||||
'is_uang': selectedStokBantuan.isUang ?? false,
|
||||
};
|
||||
|
||||
// Tambahkan skema bantuan jika ada
|
||||
@ -438,9 +449,6 @@ class DonaturDashboardController extends GetxController {
|
||||
colorText: Colors.white,
|
||||
duration: const Duration(seconds: 3),
|
||||
);
|
||||
|
||||
// Pindah ke tab riwayat penitipan
|
||||
DefaultTabController.of(Get.context!)?.animateTo(0);
|
||||
} catch (e) {
|
||||
print('Error creating penitipan bantuan: $e');
|
||||
Get.snackbar(
|
||||
|
@ -25,443 +25,9 @@ class DonaturPenitipanView extends GetView<DonaturDashboardController> {
|
||||
}
|
||||
}
|
||||
|
||||
class DonaturRiwayatPenitipanView extends GetView<DonaturDashboardController> {
|
||||
DonaturRiwayatPenitipanView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
DonaturDashboardController get controller {
|
||||
return Get.find<DonaturDashboardController>(tag: 'donatur_dashboard');
|
||||
}
|
||||
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultTabController(
|
||||
length: 3,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Riwayat Penitipan'),
|
||||
bottom: const TabBar(
|
||||
tabs: [
|
||||
Tab(text: 'Menunggu'),
|
||||
Tab(text: 'Diterima'),
|
||||
Tab(text: 'Ditolak'),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: TabBarView(
|
||||
children: [
|
||||
// Tab Menunggu
|
||||
_buildPenitipanList(context, 'MENUNGGU'),
|
||||
// Tab Diterima
|
||||
_buildPenitipanList(context, 'DITERIMA'),
|
||||
// Tab Ditolak
|
||||
_buildPenitipanList(context, 'DITOLAK'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPenitipanList(BuildContext context, String status) {
|
||||
return Obx(() {
|
||||
if (controller.isLoading.value) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
// Filter penitipan berdasarkan status
|
||||
var filteredList = controller.penitipanBantuan
|
||||
.where((item) => item.status == status)
|
||||
.toList();
|
||||
|
||||
// Filter berdasarkan pencarian
|
||||
final searchText = searchController.text.toLowerCase();
|
||||
if (searchText.isNotEmpty) {
|
||||
filteredList = filteredList.where((item) {
|
||||
final kategoriNama = item.kategoriBantuan?.nama?.toLowerCase() ?? '';
|
||||
final deskripsi = item.deskripsi?.toLowerCase() ?? '';
|
||||
final tanggal = item.tanggalPenitipan != null
|
||||
? DateFormat('dd MMMM yyyy', 'id_ID')
|
||||
.format(item.tanggalPenitipan!)
|
||||
.toLowerCase()
|
||||
: '';
|
||||
|
||||
return kategoriNama.contains(searchText) ||
|
||||
deskripsi.contains(searchText) ||
|
||||
tanggal.contains(searchText);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
await controller.fetchPenitipanBantuan();
|
||||
},
|
||||
child: filteredList.isEmpty
|
||||
? _buildEmptyState(status)
|
||||
: _buildContentList(context, filteredList, status),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildEmptyState(String status) {
|
||||
String statusText = '';
|
||||
switch (status) {
|
||||
case 'MENUNGGU':
|
||||
statusText = 'menunggu verifikasi';
|
||||
break;
|
||||
case 'DITERIMA':
|
||||
statusText = 'diterima';
|
||||
break;
|
||||
case 'DITOLAK':
|
||||
statusText = 'ditolak';
|
||||
break;
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: SingleChildScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.inventory_2_outlined,
|
||||
size: 80,
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Tidak ada penitipan $statusText',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
child: Text(
|
||||
'Anda belum memiliki riwayat penitipan yang $statusText',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildContentList(
|
||||
BuildContext context, List<dynamic> filteredList, String status) {
|
||||
Color statusColor;
|
||||
switch (status) {
|
||||
case 'DITERIMA':
|
||||
statusColor = Colors.green;
|
||||
break;
|
||||
case 'DITOLAK':
|
||||
statusColor = Colors.red;
|
||||
break;
|
||||
case 'MENUNGGU':
|
||||
default:
|
||||
statusColor = Colors.orange;
|
||||
break;
|
||||
}
|
||||
|
||||
return SingleChildScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Search field
|
||||
TextField(
|
||||
controller: searchController,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Cari riwayat penitipan...',
|
||||
prefixIcon: const Icon(Icons.search),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade100,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 0),
|
||||
),
|
||||
onChanged: (value) {
|
||||
// Trigger update dengan GetX
|
||||
controller.update();
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Info jumlah item
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Daftar Penitipan ${status.toLowerCase()}',
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${filteredList.length} item',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Daftar penitipan
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildPenitipanCard(
|
||||
context, filteredList[index], statusColor);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPenitipanCard(
|
||||
BuildContext context, dynamic penitipan, Color statusColor) {
|
||||
final formattedDate = penitipan.tanggalPenitipan != null
|
||||
? DateFormat('dd MMMM yyyy', 'id_ID')
|
||||
.format(penitipan.tanggalPenitipan!)
|
||||
: 'Tanggal tidak tersedia';
|
||||
|
||||
IconData statusIcon;
|
||||
|
||||
switch (penitipan.status) {
|
||||
case 'DITERIMA':
|
||||
statusIcon = Icons.check_circle;
|
||||
break;
|
||||
case 'DITOLAK':
|
||||
statusIcon = Icons.cancel;
|
||||
break;
|
||||
case 'MENUNGGU':
|
||||
default:
|
||||
statusIcon = Icons.hourglass_empty;
|
||||
break;
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 5),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Card(
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Icon(
|
||||
statusIcon,
|
||||
color: statusColor,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
penitipan.kategoriBantuan?.nama ?? 'Bantuan',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
penitipan.status ?? 'MENUNGGU',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: statusColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.calendar_today,
|
||||
size: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
formattedDate,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.inventory_2_outlined,
|
||||
size: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'Jumlah: ${penitipan.jumlah ?? 0}',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade800,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (penitipan.deskripsi != null &&
|
||||
penitipan.deskripsi!.isNotEmpty) ...[
|
||||
const Divider(height: 24),
|
||||
Text(
|
||||
penitipan.deskripsi!,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
if (penitipan.status == 'DITOLAK' &&
|
||||
penitipan.alasanPenolakan != null &&
|
||||
penitipan.alasanPenolakan!.isNotEmpty) ...[
|
||||
const Divider(height: 24),
|
||||
Text(
|
||||
'Alasan Penolakan:',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.red.shade700,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
penitipan.alasanPenolakan!,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.red.shade700,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildContactInfo({
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required String content,
|
||||
}) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade50,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: Colors.blue,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
content,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FormPenitipanBantuan extends StatefulWidget {
|
||||
const FormPenitipanBantuan({super.key});
|
||||
|
||||
@override
|
||||
_FormPenitipanBantuanState createState() => _FormPenitipanBantuanState();
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/modules/donatur/controllers/donatur_dashboard_controller.dart';
|
||||
|
||||
class DonaturRiwayatPenitipanView extends GetView<DonaturDashboardController> {
|
||||
DonaturRiwayatPenitipanView({Key? key}) : super(key: key);
|
||||
DonaturRiwayatPenitipanView({super.key});
|
||||
|
||||
@override
|
||||
DonaturDashboardController get controller {
|
||||
@ -23,7 +23,7 @@ class DonaturRiwayatPenitipanView extends GetView<DonaturDashboardController> {
|
||||
bottom: const TabBar(
|
||||
tabs: [
|
||||
Tab(text: 'Menunggu'),
|
||||
Tab(text: 'Diterima'),
|
||||
Tab(text: 'Terverifikasi'),
|
||||
Tab(text: 'Ditolak'),
|
||||
],
|
||||
),
|
||||
@ -33,7 +33,7 @@ class DonaturRiwayatPenitipanView extends GetView<DonaturDashboardController> {
|
||||
// Tab Menunggu
|
||||
_buildPenitipanList(context, 'MENUNGGU'),
|
||||
// Tab Diterima
|
||||
_buildPenitipanList(context, 'DITERIMA'),
|
||||
_buildPenitipanList(context, 'TERVERIFIKASI'),
|
||||
// Tab Ditolak
|
||||
_buildPenitipanList(context, 'DITOLAK'),
|
||||
],
|
||||
@ -88,8 +88,8 @@ class DonaturRiwayatPenitipanView extends GetView<DonaturDashboardController> {
|
||||
case 'MENUNGGU':
|
||||
statusText = 'menunggu verifikasi';
|
||||
break;
|
||||
case 'DITERIMA':
|
||||
statusText = 'diterima';
|
||||
case 'TERVERIFIKASI':
|
||||
statusText = 'terverifikasi';
|
||||
break;
|
||||
case 'DITOLAK':
|
||||
statusText = 'ditolak';
|
||||
@ -137,7 +137,7 @@ class DonaturRiwayatPenitipanView extends GetView<DonaturDashboardController> {
|
||||
BuildContext context, List<dynamic> filteredList, String status) {
|
||||
Color statusColor;
|
||||
switch (status) {
|
||||
case 'DITERIMA':
|
||||
case 'TERVERIFIKASI':
|
||||
statusColor = Colors.green;
|
||||
break;
|
||||
case 'DITOLAK':
|
||||
@ -221,7 +221,7 @@ class DonaturRiwayatPenitipanView extends GetView<DonaturDashboardController> {
|
||||
IconData statusIcon;
|
||||
|
||||
switch (penitipan.status) {
|
||||
case 'DITERIMA':
|
||||
case 'TERVERIFIKASI':
|
||||
statusIcon = Icons.check_circle;
|
||||
break;
|
||||
case 'DITOLAK':
|
||||
@ -233,160 +233,397 @@ class DonaturRiwayatPenitipanView extends GetView<DonaturDashboardController> {
|
||||
break;
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 5),
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
print('Debug: Tapped on penitipan with ID: ${penitipan.id}');
|
||||
_showDetailDialog(context, penitipan);
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 5),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Card(
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
child: Card(
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Icon(
|
||||
statusIcon,
|
||||
color: statusColor,
|
||||
size: 24,
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Icon(
|
||||
statusIcon,
|
||||
color: statusColor,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
penitipan.kategoriBantuan?.nama ??
|
||||
'Bantuan',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
penitipan.status ?? 'MENUNGGU',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: statusColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.calendar_today,
|
||||
size: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
formattedDate,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.inventory_2_outlined,
|
||||
size: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'Jumlah: ${penitipan.jumlah ?? 0}',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade800,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
penitipan.kategoriBantuan?.nama ?? 'Bantuan',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
if (penitipan.deskripsi != null &&
|
||||
penitipan.deskripsi!.isNotEmpty) ...[
|
||||
const Divider(height: 24),
|
||||
Text(
|
||||
penitipan.deskripsi!,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
if (penitipan.status == 'DITOLAK' &&
|
||||
penitipan.alasanPenolakan != null &&
|
||||
penitipan.alasanPenolakan!.isNotEmpty) ...[
|
||||
const Divider(height: 24),
|
||||
Text(
|
||||
'Alasan Penolakan:',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.red.shade700,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
penitipan.alasanPenolakan!,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.red.shade700,
|
||||
),
|
||||
),
|
||||
],
|
||||
// Tambahkan petunjuk visual
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
size: 14,
|
||||
color: Colors.blue.shade700,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'Tap untuk detail',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.blue.shade700,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
penitipan.status ?? 'MENUNGGU',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: statusColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.calendar_today,
|
||||
size: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
formattedDate,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.inventory_2_outlined,
|
||||
size: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'Jumlah: ${penitipan.jumlah ?? 0}',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade800,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (penitipan.deskripsi != null &&
|
||||
penitipan.deskripsi!.isNotEmpty) ...[
|
||||
const Divider(height: 24),
|
||||
Text(
|
||||
penitipan.deskripsi!,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showDetailDialog(BuildContext context, dynamic penitipan) {
|
||||
final isUang = penitipan.isUang ?? false;
|
||||
final kategoriSatuan = penitipan.kategoriBantuan?.satuan ?? '';
|
||||
|
||||
String getPetugasDesaNama(String? id) {
|
||||
return id != null ? 'Petugas Desa' : 'Tidak ada petugas';
|
||||
}
|
||||
|
||||
void showFullScreenImage(String imageUrl) {
|
||||
Get.dialog(
|
||||
Dialog(
|
||||
insetPadding: EdgeInsets.zero,
|
||||
child: Container(
|
||||
color: Colors.black,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
InteractiveViewer(
|
||||
panEnabled: true,
|
||||
minScale: 0.5,
|
||||
maxScale: 4,
|
||||
child: Image.network(
|
||||
imageUrl,
|
||||
fit: BoxFit.contain,
|
||||
loadingBuilder: (context, child, loadingProgress) {
|
||||
if (loadingProgress == null) return child;
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
value: loadingProgress.expectedTotalBytes != null
|
||||
? loadingProgress.cumulativeBytesLoaded /
|
||||
loadingProgress.expectedTotalBytes!
|
||||
: null,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 20,
|
||||
right: 20,
|
||||
child: GestureDetector(
|
||||
onTap: () => Get.back(),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withOpacity(0.5),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
if (penitipan.status == 'DITOLAK' &&
|
||||
penitipan.alasanPenolakan != null &&
|
||||
penitipan.alasanPenolakan!.isNotEmpty) ...[
|
||||
const Divider(height: 24),
|
||||
Text(
|
||||
'Alasan Penolakan:',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: const Text('Detail Penitipan'),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildInfoRow('ID', penitipan.id ?? '-'),
|
||||
_buildInfoRow('Kategori', penitipan.kategoriBantuan?.nama ?? '-'),
|
||||
_buildInfoRow(
|
||||
'Jumlah',
|
||||
isUang
|
||||
? 'Rp ${penitipan.jumlah?.toStringAsFixed(0) ?? '0'}'
|
||||
: '${penitipan.jumlah?.toString() ?? '0'} $kategoriSatuan',
|
||||
),
|
||||
_buildInfoRow(
|
||||
'Tanggal Penitipan',
|
||||
penitipan.tanggalPenitipan != null
|
||||
? DateFormat('dd MMMM yyyy', 'id_ID')
|
||||
.format(penitipan.tanggalPenitipan!)
|
||||
: 'Tanggal tidak tersedia',
|
||||
),
|
||||
_buildInfoRow(
|
||||
'Status',
|
||||
penitipan.status ?? 'Belum diproses',
|
||||
),
|
||||
if (penitipan.tanggalVerifikasi != null)
|
||||
_buildInfoRow(
|
||||
'Tanggal Verifikasi',
|
||||
DateFormat('dd MMMM yyyy HH:mm', 'id_ID')
|
||||
.format(penitipan.tanggalVerifikasi!),
|
||||
),
|
||||
if (penitipan.deskripsi != null &&
|
||||
penitipan.deskripsi!.isNotEmpty)
|
||||
_buildInfoRow('Deskripsi', penitipan.deskripsi!),
|
||||
if (penitipan.alasanPenolakan != null &&
|
||||
penitipan.alasanPenolakan!.isNotEmpty)
|
||||
_buildInfoRow('Alasan Penolakan', penitipan.alasanPenolakan!),
|
||||
|
||||
// Gambar bukti penitipan
|
||||
if (penitipan.fotoBantuan != null &&
|
||||
penitipan.fotoBantuan!.isNotEmpty) ...[
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Bukti Penitipan',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.red.shade700,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
penitipan.alasanPenolakan!,
|
||||
const SizedBox(height: 8),
|
||||
GestureDetector(
|
||||
onTap: () =>
|
||||
showFullScreenImage(penitipan.fotoBantuan!.first),
|
||||
child: Container(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
image: DecorationImage(
|
||||
image: NetworkImage(penitipan.fotoBantuan!.first),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
// Bukti serah terima jika ada
|
||||
if (penitipan.fotoBuktiSerahTerima != null &&
|
||||
penitipan.fotoBuktiSerahTerima!.isNotEmpty) ...[
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Bukti Serah Terima',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
color: Colors.red.shade700,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
GestureDetector(
|
||||
onTap: () =>
|
||||
showFullScreenImage(penitipan.fotoBuktiSerahTerima!),
|
||||
child: Container(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
image: DecorationImage(
|
||||
image: NetworkImage(penitipan.fotoBuktiSerahTerima!),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
child: const Text(
|
||||
'Tutup',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoRow(String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/modules/donatur/controllers/donatur_dashboard_controller.dart';
|
||||
import 'package:penyaluran_app/app/widgets/section_header.dart';
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'package:penyaluran_app/app/modules/donatur/views/donatur_skema_view.dart
|
||||
import 'package:penyaluran_app/app/modules/donatur/views/donatur_jadwal_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/donatur/views/donatur_laporan_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/donatur/views/donatur_penitipan_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/donatur/views/donatur_riwayat_penitipan_view.dart';
|
||||
import 'package:penyaluran_app/app/widgets/app_bottom_navigation_bar.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
|
||||
|
@ -891,13 +891,14 @@ class LaporanPenyaluranController extends GetxController {
|
||||
final stokBantuan = daftarPenerima
|
||||
.firstWhere((p) => p.stokBantuanId == stokId,
|
||||
orElse: () => PenerimaPenyaluranModel())
|
||||
?.stokBantuan;
|
||||
.stokBantuan;
|
||||
|
||||
if (stokBantuan == null)
|
||||
if (stokBantuan == null) {
|
||||
return pw.TableRow(children: [
|
||||
_buildPdfTableCell('-', ttf),
|
||||
_buildPdfTableCell('-', ttf),
|
||||
]);
|
||||
}
|
||||
|
||||
final isUang = stokBantuan['is_uang'] == true;
|
||||
final formattedJumlah = isUang
|
||||
@ -912,7 +913,7 @@ class LaporanPenyaluranController extends GetxController {
|
||||
align: pw.TextAlign.center),
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
}),
|
||||
],
|
||||
),
|
||||
],
|
||||
@ -988,7 +989,7 @@ class LaporanPenyaluranController extends GetxController {
|
||||
align: pw.TextAlign.center),
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
}),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
@ -10,7 +10,7 @@ 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);
|
||||
const LaporanPenyaluranCreateView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -11,7 +11,7 @@ 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);
|
||||
const LaporanPenyaluranDetailView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -385,8 +385,9 @@ class LaporanPenyaluranDetailView extends GetView<LaporanPenyaluranController> {
|
||||
orElse: () => PenerimaPenyaluranModel())
|
||||
.stokBantuan;
|
||||
|
||||
if (stokBantuan == null)
|
||||
if (stokBantuan == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
final kategori =
|
||||
stokBantuan['kategori_bantuan'] != null
|
||||
@ -939,9 +940,9 @@ class LaporanPenyaluranDetailView extends GetView<LaporanPenyaluranController> {
|
||||
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
final Uri _url = Uri.parse(url);
|
||||
if (await canLaunchUrl(_url)) {
|
||||
await launchUrl(_url, mode: LaunchMode.externalApplication);
|
||||
final Uri url0 = Uri.parse(url);
|
||||
if (await canLaunchUrl(url0)) {
|
||||
await launchUrl(url0, mode: LaunchMode.externalApplication);
|
||||
} else {
|
||||
Get.snackbar(
|
||||
'Error',
|
||||
|
@ -8,7 +8,7 @@ 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);
|
||||
const LaporanPenyaluranEditView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -10,7 +10,7 @@ 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);
|
||||
const LaporanPenyaluranView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -39,35 +39,14 @@ class DetailPenyaluranController extends GetxController {
|
||||
if (penyaluran.value?.id != null) {
|
||||
loadPenyaluranDetails(penyaluran.value!.id!);
|
||||
}
|
||||
checkUserRole();
|
||||
} else if (penyaluranId != null) {
|
||||
// Jika hanya ID penyaluran yang diterima
|
||||
loadPenyaluranData(penyaluranId);
|
||||
checkUserRole();
|
||||
} else {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> checkUserRole() async {
|
||||
try {
|
||||
final user = _supabaseService.client.auth.currentUser;
|
||||
if (user != null) {
|
||||
final userData = await _supabaseService.client
|
||||
.from('user_profile')
|
||||
.select('role')
|
||||
.eq('id', user.id)
|
||||
.single();
|
||||
|
||||
if (userData['role'] == 'PETUGASDESA') {
|
||||
isPetugasDesa.value = true;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error checking user role: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadPenyaluranData(String penyaluranId) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
@ -522,36 +501,33 @@ class DetailPenyaluranController extends GetxController {
|
||||
.eq('qr_code_hash', qrHash)
|
||||
.single();
|
||||
|
||||
if (data != null) {
|
||||
// Jika penerima ditemukan, konversi ke model
|
||||
final Map<String, dynamic> sanitizedPenerimaData =
|
||||
Map<String, dynamic>.from(data);
|
||||
// Jika penerima ditemukan, konversi ke model
|
||||
final Map<String, dynamic> sanitizedPenerimaData =
|
||||
Map<String, dynamic>.from(data);
|
||||
|
||||
// Konversi jumlah_bantuan ke double jika bertipe String
|
||||
if (sanitizedPenerimaData['jumlah_bantuan'] is String) {
|
||||
sanitizedPenerimaData['jumlah_bantuan'] = double.tryParse(
|
||||
sanitizedPenerimaData['jumlah_bantuan'] as String);
|
||||
}
|
||||
|
||||
// Konversi data ke model
|
||||
final penerima =
|
||||
PenerimaPenyaluranModel.fromJson(sanitizedPenerimaData);
|
||||
|
||||
// Set isProcessing ke false sebelum navigasi untuk menghindari masalah loading
|
||||
isProcessing.value = false;
|
||||
|
||||
// Navigasi ke halaman konfirmasi dengan data terbaru
|
||||
await Get.toNamed('/petugas-desa/konfirmasi-penerima/${penerima.id}',
|
||||
arguments: {
|
||||
'penerima': penerima,
|
||||
'tanggal_penyaluran': penyaluran.value?.tanggalPenyaluran
|
||||
});
|
||||
|
||||
// Refresh data
|
||||
await refreshData();
|
||||
return true;
|
||||
// Konversi jumlah_bantuan ke double jika bertipe String
|
||||
if (sanitizedPenerimaData['jumlah_bantuan'] is String) {
|
||||
sanitizedPenerimaData['jumlah_bantuan'] =
|
||||
double.tryParse(sanitizedPenerimaData['jumlah_bantuan'] as String);
|
||||
}
|
||||
|
||||
// Konversi data ke model
|
||||
final penerima = PenerimaPenyaluranModel.fromJson(sanitizedPenerimaData);
|
||||
|
||||
// Set isProcessing ke false sebelum navigasi untuk menghindari masalah loading
|
||||
isProcessing.value = false;
|
||||
|
||||
// Navigasi ke halaman konfirmasi dengan data terbaru
|
||||
await Get.toNamed('/petugas-desa/konfirmasi-penerima/${penerima.id}',
|
||||
arguments: {
|
||||
'penerima': penerima,
|
||||
'tanggal_penyaluran': penyaluran.value?.tanggalPenyaluran
|
||||
});
|
||||
|
||||
// Refresh data
|
||||
await refreshData();
|
||||
return true;
|
||||
|
||||
return false;
|
||||
} catch (e) {
|
||||
print('Error verifikasi QR code: $e');
|
||||
|
@ -448,7 +448,7 @@ class JadwalPenyaluranController extends GetxController {
|
||||
.eq('id', stokBantuanId)
|
||||
.single();
|
||||
|
||||
if (stokData != null && stokData['total_stok'] != null) {
|
||||
if (stokData['total_stok'] != null) {
|
||||
final currentStok = stokData['total_stok'].toDouble();
|
||||
final newStok = currentStok - totalStokDibutuhkan;
|
||||
|
||||
|
@ -197,9 +197,63 @@ class PenitipanBantuanController extends GetxController {
|
||||
}
|
||||
|
||||
Future<void> pickfotoBuktiSerahTerima() async {
|
||||
try {
|
||||
// Tampilkan bottom sheet untuk memilih sumber foto
|
||||
Get.bottomSheet(
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Pilih Sumber Foto',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.camera_alt),
|
||||
title: const Text('Kamera'),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
_pickfotoBuktiSerahTerimaFrom(ImageSource.camera);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.photo_library),
|
||||
title: const Text('Galeri'),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
_pickfotoBuktiSerahTerimaFrom(ImageSource.gallery);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
print('Error showing bottom sheet: $e');
|
||||
Get.snackbar(
|
||||
'Error',
|
||||
'Terjadi kesalahan: ${e.toString()}',
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Fungsi helper untuk mengambil foto dari sumber yang dipilih
|
||||
Future<void> _pickfotoBuktiSerahTerimaFrom(ImageSource source) async {
|
||||
try {
|
||||
final pickedFile = await _imagePicker.pickImage(
|
||||
source: ImageSource.camera,
|
||||
source: source,
|
||||
imageQuality: 70,
|
||||
maxWidth: 1000,
|
||||
);
|
||||
|
@ -74,9 +74,7 @@ class PetugasDesaController extends GetxController {
|
||||
String get nama {
|
||||
// 1. Coba ambil dari AuthController displayName yang paling lengkap
|
||||
final authDisplayName = _authController.displayName;
|
||||
if (authDisplayName != null &&
|
||||
authDisplayName != 'Pengguna' &&
|
||||
authDisplayName != user?.email) {
|
||||
if (authDisplayName != 'Pengguna' && authDisplayName != user?.email) {
|
||||
return authDisplayName;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/routes/app_pages.dart';
|
||||
import 'package:penyaluran_app/app/utils/date_time_helper.dart';
|
||||
import 'package:percent_indicator/circular_percent_indicator.dart';
|
||||
|
@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/donatur_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
import 'package:penyaluran_app/app/data/models/donatur_model.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penitipan_bantuan_model.dart';
|
||||
import 'package:penyaluran_app/app/widgets/dialogs/detail_penitipan_dialog.dart';
|
||||
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/penerima_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/utils/date_time_helper.dart';
|
||||
|
||||
class DetailPenerimaView extends GetView<PenerimaController> {
|
||||
|
@ -743,10 +743,10 @@ class _KonfirmasiPenerimaPageState extends State<KonfirmasiPenerimaPage> {
|
||||
|
||||
// Hapus file sementara sebelum navigasi
|
||||
try {
|
||||
if (signatureFile != null && signatureFile.existsSync()) {
|
||||
if (signatureFile.existsSync()) {
|
||||
await signatureFile.delete();
|
||||
}
|
||||
if (tempDir != null && tempDir.existsSync()) {
|
||||
if (tempDir.existsSync()) {
|
||||
await tempDir.delete();
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -632,18 +632,26 @@ class PenitipanView extends GetView<PenitipanBantuanController> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.camera_alt,
|
||||
Icons.add_photo_alternate,
|
||||
size: 48,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Ambil Foto',
|
||||
'Pilih Foto',
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade600,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Kamera atau Galeri',
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -426,7 +426,9 @@ class StokBantuanView extends GetView<StokBantuanController> {
|
||||
context,
|
||||
icon: Icons.access_time,
|
||||
label: 'Terakhir Diperbarui',
|
||||
value: DateTimeHelper.formatDateTime(item.updatedAt),
|
||||
value: item.updatedAt != null
|
||||
? '${item.updatedAt!.day}/${item.updatedAt!.month}/${item.updatedAt!.year} ${item.updatedAt!.hour}:${item.updatedAt!.minute}'
|
||||
: 'Tidak ada data',
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -90,29 +90,20 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
||||
|
||||
print('stokData $stokData');
|
||||
|
||||
if (stokData != null) {
|
||||
namaStokBantuan.value =
|
||||
stokData['nama'] ?? 'Nama stok tidak tersedia';
|
||||
satuanStokBantuan.value = stokData['satuan'] ?? 'Tidak ada satuan';
|
||||
isUang.value = stokData['is_uang'] ?? false;
|
||||
namaStokBantuan.value = stokData['nama'] ?? 'Nama stok tidak tersedia';
|
||||
satuanStokBantuan.value = stokData['satuan'] ?? 'Tidak ada satuan';
|
||||
isUang.value = stokData['is_uang'] ?? false;
|
||||
|
||||
// Ambil jumlah stok tersedia
|
||||
if (stokData['total_stok'] != null) {
|
||||
totalStokTersedia.value = stokData['total_stok'].toDouble();
|
||||
} else {
|
||||
totalStokTersedia.value = 0;
|
||||
}
|
||||
|
||||
// Periksa kecukupan stok
|
||||
isStokCukup.value =
|
||||
totalStokTersedia.value >= totalStokDibutuhkan.value;
|
||||
// Ambil jumlah stok tersedia
|
||||
if (stokData['total_stok'] != null) {
|
||||
totalStokTersedia.value = stokData['total_stok'].toDouble();
|
||||
} else {
|
||||
namaStokBantuan.value = 'Stok tidak ditemukan';
|
||||
satuanStokBantuan.value = '';
|
||||
totalStokTersedia.value = 0;
|
||||
isStokCukup.value = false;
|
||||
isUang.value = false;
|
||||
}
|
||||
|
||||
// Periksa kecukupan stok
|
||||
isStokCukup.value =
|
||||
totalStokTersedia.value >= totalStokDibutuhkan.value;
|
||||
} catch (e) {
|
||||
print('Error loading stok bantuan: $e');
|
||||
namaStokBantuan.value = 'Error memuat data stok';
|
||||
|
@ -4,7 +4,6 @@ import 'package:penyaluran_app/app/data/models/user_model.dart';
|
||||
import 'package:penyaluran_app/app/services/supabase_service.dart';
|
||||
import 'package:penyaluran_app/app/modules/auth/controllers/auth_controller.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'dart:io';
|
||||
|
||||
class ProfileController extends GetxController {
|
||||
final SupabaseService _supabaseService = Get.find<SupabaseService>();
|
||||
|
@ -743,10 +743,10 @@ class ProfileView extends GetView<ProfileController> {
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
child: const Text('Batal'),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.grey[700],
|
||||
),
|
||||
child: const Text('Batal'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
|
@ -125,7 +125,7 @@ class WargaDashboardController extends GetxController {
|
||||
print('DEBUG WARGA: Memuat data user dari AuthController');
|
||||
print('DEBUG WARGA: baseUser: ${_authController.baseUser}');
|
||||
print('DEBUG WARGA: roleData: ${_authController.roleData}');
|
||||
print('DEBUG WARGA: nama yang akan ditampilkan: ${nama}');
|
||||
print('DEBUG WARGA: nama yang akan ditampilkan: $nama');
|
||||
print(
|
||||
'DEBUG WARGA: displayName dari auth controller: ${_authController.displayName}');
|
||||
|
||||
|
@ -539,7 +539,7 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
}),
|
||||
],
|
||||
if (totalUang == 0 && totalNonUang.isEmpty)
|
||||
_buildSummaryItem(
|
||||
|
@ -4,7 +4,6 @@ import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penerima_penyaluran_model.dart';
|
||||
import 'package:penyaluran_app/app/data/models/pengaduan_model.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
import 'package:penyaluran_app/app/widgets/status_badge.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
@ -265,18 +265,16 @@ class SupabaseService extends GetxService {
|
||||
}
|
||||
|
||||
// Tambahkan data role-specific
|
||||
if (roleData != null) {
|
||||
combinedData['role_data'] = roleData;
|
||||
combinedData['role_data'] = roleData;
|
||||
|
||||
// Tambahkan data desa jika ada
|
||||
if (roleData['desa'] != null) {
|
||||
combinedData['desa'] = roleData['desa'];
|
||||
}
|
||||
// Tambahkan data desa jika ada
|
||||
if (roleData['desa'] != null) {
|
||||
combinedData['desa'] = roleData['desa'];
|
||||
}
|
||||
|
||||
// Tambahkan nama dari data role jika ada
|
||||
if (roleData['nama_lengkap'] != null) {
|
||||
combinedData['name'] = roleData['nama_lengkap'];
|
||||
}
|
||||
// Tambahkan nama dari data role jika ada
|
||||
if (roleData['nama_lengkap'] != null) {
|
||||
combinedData['name'] = roleData['nama_lengkap'];
|
||||
}
|
||||
|
||||
// Cache profil untuk penggunaan berikutnya
|
||||
@ -783,6 +781,8 @@ class SupabaseService extends GetxService {
|
||||
Future<String?> uploadFile(
|
||||
String filePath, String bucket, String folder) async {
|
||||
try {
|
||||
print(
|
||||
'Uploading file from path: $filePath to bucket: $bucket in folder: $folder');
|
||||
final fileName = filePath.split('/').last;
|
||||
final fileExt = fileName.split('.').last;
|
||||
final fileKey =
|
||||
@ -1327,10 +1327,6 @@ class SupabaseService extends GetxService {
|
||||
.eq('role_name', 'warga')
|
||||
.single();
|
||||
|
||||
if (roleResponse == null) {
|
||||
throw 'Role warga tidak ditemukan';
|
||||
}
|
||||
|
||||
final roleId = roleResponse['id'];
|
||||
|
||||
// Update role_id di auth.users
|
||||
@ -1379,10 +1375,6 @@ class SupabaseService extends GetxService {
|
||||
.eq('role_name', 'donatur')
|
||||
.single();
|
||||
|
||||
if (roleResponse == null) {
|
||||
throw 'Role donatur tidak ditemukan';
|
||||
}
|
||||
|
||||
final roleId = roleResponse['id'];
|
||||
|
||||
// Update role_id di auth.users
|
||||
@ -1477,10 +1469,6 @@ class SupabaseService extends GetxService {
|
||||
.eq('role_name', 'petugas_desa')
|
||||
.single();
|
||||
|
||||
if (roleResponse == null) {
|
||||
throw 'Role petugas desa tidak ditemukan';
|
||||
}
|
||||
|
||||
final roleId = roleResponse['id'];
|
||||
|
||||
// Update role_id di auth.users
|
||||
|
Reference in New Issue
Block a user