Perbarui model dan tampilan untuk mendukung status penyaluran dalam aplikasi. Tambahkan properti statusPenyaluran pada PenerimaPenyaluranModel dan SkemaBantuanModel. Modifikasi tampilan di BantuanCard dan StatusBadge untuk menampilkan status penyaluran dengan lebih baik. Hapus penggunaan prioritas di beberapa model dan tampilan untuk menyederhanakan kode. Implementasikan logika baru di JadwalPenyaluranController untuk memperbarui stok bantuan berdasarkan jumlah yang diterima.
This commit is contained in:
@ -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 NJ<EFBFBD><EFBFBD><EFBFBD>2<18> <20><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>
|
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint <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\arm64-v8a\additional_project_files.txt NJ<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 <EFBFBD><EFBFBD><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 NJ<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 <EFBFBD><EFBFBD><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\arm64-v8a\android_gradle_build_mini.json NJ<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 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><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 NJ<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 <EFBFBD><EFBFBD><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\arm64-v8a\build.ninja.txt NJ<EFBFBD><EFBFBD><EFBFBD>2y
|
pD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build.ninja.txt <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2y
|
||||||
w
|
w
|
||||||
uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build_file_index.txt NJ<EFBFBD><EFBFBD><EFBFBD>2
|
uD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\arm64-v8a\build_file_index.txt <EFBFBD><EFBFBD><EFBFBD><EFBFBD><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><EFBFBD><EFBFBD>2 ~
|
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
|
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>
|
||||||
<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
|
<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
|
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
|
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><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\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>
|
||||||
<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
|
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
|
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
|
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|
|
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>
|
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
|
|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>
|
||||||
<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
|
<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
|
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
|
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><EFBFBD><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><EFBFBD><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><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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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><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 <08><><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 <08><><EFBFBD><EFBFBD><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 <08><><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 <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\x86_64\android_gradle_build_mini.json <08><><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 <08><><EFBFBD><EFBFBD><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 <08><><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 <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_64\build.ninja.txt <08><><EFBFBD><EFBFBD><EFBFBD>2v
|
mD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build.ninja.txt <08><><EFBFBD><EFBFBD><EFBFBD>2v
|
||||||
t
|
t
|
||||||
rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build_file_index.txt <08><><EFBFBD><EFBFBD><EFBFBD>2
|
rD:\KULIAH\Matkul\SKRIPSI\penyaluran_app\penyaluran_app\android\app\.cxx\Debug\626b5o2n\x86_64\build_file_index.txt <08><><EFBFBD><EFBFBD><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 <08><><EFBFBD><EFBFBD><EFBFBD>2 {
|
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
|
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>
|
<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
|
}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
|
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
|
@ -23,6 +23,7 @@ class PenerimaPenyaluranModel {
|
|||||||
final String? lokasiPenyaluranNama; // Nama lokasi penyaluran
|
final String? lokasiPenyaluranNama; // Nama lokasi penyaluran
|
||||||
final String? lokasiPenyaluranAlamat; // Alamat lokasi penyaluran
|
final String? lokasiPenyaluranAlamat; // Alamat lokasi penyaluran
|
||||||
final String? qrCodeHash; // Hash untuk QR code
|
final String? qrCodeHash; // Hash untuk QR code
|
||||||
|
final String? statusPenyaluran; // Status penyaluran
|
||||||
|
|
||||||
PenerimaPenyaluranModel({
|
PenerimaPenyaluranModel({
|
||||||
this.id,
|
this.id,
|
||||||
@ -47,6 +48,7 @@ class PenerimaPenyaluranModel {
|
|||||||
this.lokasiPenyaluranNama,
|
this.lokasiPenyaluranNama,
|
||||||
this.lokasiPenyaluranAlamat,
|
this.lokasiPenyaluranAlamat,
|
||||||
this.qrCodeHash,
|
this.qrCodeHash,
|
||||||
|
this.statusPenyaluran,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory PenerimaPenyaluranModel.fromRawJson(String str) =>
|
factory PenerimaPenyaluranModel.fromRawJson(String str) =>
|
||||||
@ -82,6 +84,7 @@ class PenerimaPenyaluranModel {
|
|||||||
lokasiPenyaluranNama: json["lokasi_penyaluran_nama"],
|
lokasiPenyaluranNama: json["lokasi_penyaluran_nama"],
|
||||||
lokasiPenyaluranAlamat: json["lokasi_penyaluran_alamat"],
|
lokasiPenyaluranAlamat: json["lokasi_penyaluran_alamat"],
|
||||||
qrCodeHash: json["qr_code_hash"],
|
qrCodeHash: json["qr_code_hash"],
|
||||||
|
statusPenyaluran: json["status_penyaluran"],
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
@ -107,5 +110,6 @@ class PenerimaPenyaluranModel {
|
|||||||
"lokasi_penyaluran_nama": lokasiPenyaluranNama,
|
"lokasi_penyaluran_nama": lokasiPenyaluranNama,
|
||||||
"lokasi_penyaluran_alamat": lokasiPenyaluranAlamat,
|
"lokasi_penyaluran_alamat": lokasiPenyaluranAlamat,
|
||||||
"qr_code_hash": qrCodeHash,
|
"qr_code_hash": qrCodeHash,
|
||||||
|
"status_penyaluran": statusPenyaluran,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ class SkemaBantuanModel {
|
|||||||
final DateTime? updatedAt;
|
final DateTime? updatedAt;
|
||||||
final String? stokBantuanId;
|
final String? stokBantuanId;
|
||||||
final String? kategoriBantuanId;
|
final String? kategoriBantuanId;
|
||||||
|
final double? jumlahDiterimaPerOrang;
|
||||||
|
|
||||||
SkemaBantuanModel({
|
SkemaBantuanModel({
|
||||||
this.id,
|
this.id,
|
||||||
@ -23,6 +24,7 @@ class SkemaBantuanModel {
|
|||||||
this.updatedAt,
|
this.updatedAt,
|
||||||
this.stokBantuanId,
|
this.stokBantuanId,
|
||||||
this.kategoriBantuanId,
|
this.kategoriBantuanId,
|
||||||
|
this.jumlahDiterimaPerOrang,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory SkemaBantuanModel.fromRawJson(String str) =>
|
factory SkemaBantuanModel.fromRawJson(String str) =>
|
||||||
@ -46,6 +48,9 @@ class SkemaBantuanModel {
|
|||||||
: null,
|
: null,
|
||||||
stokBantuanId: json["stok_bantuan_id"],
|
stokBantuanId: json["stok_bantuan_id"],
|
||||||
kategoriBantuanId: json["kategori_bantuan_id"],
|
kategoriBantuanId: json["kategori_bantuan_id"],
|
||||||
|
jumlahDiterimaPerOrang: json["jumlah_diterima_per_orang"] != null
|
||||||
|
? json["jumlah_diterima_per_orang"].toDouble()
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
@ -59,5 +64,6 @@ class SkemaBantuanModel {
|
|||||||
"updated_at": updatedAt?.toIso8601String(),
|
"updated_at": updatedAt?.toIso8601String(),
|
||||||
"stok_bantuan_id": stokBantuanId,
|
"stok_bantuan_id": stokBantuanId,
|
||||||
"kategori_bantuan_id": kategoriBantuanId,
|
"kategori_bantuan_id": kategoriBantuanId,
|
||||||
|
"jumlah_diterima_per_orang": jumlahDiterimaPerOrang,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ class TindakanPengaduanModel {
|
|||||||
final String? tindakan;
|
final String? tindakan;
|
||||||
final String? catatan;
|
final String? catatan;
|
||||||
final String? statusTindakan; // PROSES, SELESAI
|
final String? statusTindakan; // PROSES, SELESAI
|
||||||
final String? prioritas; // RENDAH, SEDANG, TINGGI
|
|
||||||
final String? kategoriTindakan; // Kategori tindakan enum
|
final String? kategoriTindakan; // Kategori tindakan enum
|
||||||
final String? petugasId;
|
final String? petugasId;
|
||||||
final String? verifikatorId;
|
final String? verifikatorId;
|
||||||
@ -27,7 +26,6 @@ class TindakanPengaduanModel {
|
|||||||
this.tindakan,
|
this.tindakan,
|
||||||
this.catatan,
|
this.catatan,
|
||||||
this.statusTindakan,
|
this.statusTindakan,
|
||||||
this.prioritas,
|
|
||||||
this.kategoriTindakan,
|
this.kategoriTindakan,
|
||||||
this.petugasId,
|
this.petugasId,
|
||||||
this.verifikatorId,
|
this.verifikatorId,
|
||||||
@ -55,7 +53,6 @@ class TindakanPengaduanModel {
|
|||||||
tindakan: json["tindakan"],
|
tindakan: json["tindakan"],
|
||||||
catatan: json["catatan"],
|
catatan: json["catatan"],
|
||||||
statusTindakan: json["status_tindakan"],
|
statusTindakan: json["status_tindakan"],
|
||||||
prioritas: json["prioritas"],
|
|
||||||
kategoriTindakan: json["kategori_tindakan"],
|
kategoriTindakan: json["kategori_tindakan"],
|
||||||
petugasId: json["petugas_id"],
|
petugasId: json["petugas_id"],
|
||||||
verifikatorId: json["verifikator_id"],
|
verifikatorId: json["verifikator_id"],
|
||||||
@ -76,9 +73,7 @@ class TindakanPengaduanModel {
|
|||||||
updatedAt: json["updated_at"] != null
|
updatedAt: json["updated_at"] != null
|
||||||
? DateTime.parse(json["updated_at"])
|
? DateTime.parse(json["updated_at"])
|
||||||
: null,
|
: null,
|
||||||
biayaTindakan: json["biaya_tindakan"] != null
|
biayaTindakan: json["biaya_tindakan"]?.toDouble(),
|
||||||
? double.parse(json["biaya_tindakan"].toString())
|
|
||||||
: null,
|
|
||||||
petugas: json["petugas"],
|
petugas: json["petugas"],
|
||||||
verifikator: json["verifikator"],
|
verifikator: json["verifikator"],
|
||||||
);
|
);
|
||||||
@ -89,7 +84,6 @@ class TindakanPengaduanModel {
|
|||||||
"tindakan": tindakan,
|
"tindakan": tindakan,
|
||||||
"catatan": catatan,
|
"catatan": catatan,
|
||||||
"status_tindakan": statusTindakan,
|
"status_tindakan": statusTindakan,
|
||||||
"prioritas": prioritas,
|
|
||||||
"kategori_tindakan": kategoriTindakan,
|
"kategori_tindakan": kategoriTindakan,
|
||||||
"petugas_id": petugasId,
|
"petugas_id": petugasId,
|
||||||
"verifikator_id": verifikatorId,
|
"verifikator_id": verifikatorId,
|
||||||
@ -137,20 +131,6 @@ class TindakanPengaduanModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getter untuk mendapatkan prioritas yang lebih user-friendly
|
|
||||||
String get prioritasText {
|
|
||||||
switch (prioritas) {
|
|
||||||
case 'RENDAH':
|
|
||||||
return 'Prioritas Rendah';
|
|
||||||
case 'SEDANG':
|
|
||||||
return 'Prioritas Sedang';
|
|
||||||
case 'TINGGI':
|
|
||||||
return 'Prioritas Tinggi';
|
|
||||||
default:
|
|
||||||
return prioritas ?? 'Tidak Diketahui';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getter untuk mendapatkan kategori tindakan yang lebih user-friendly
|
// Getter untuk mendapatkan kategori tindakan yang lebih user-friendly
|
||||||
String get kategoriTindakanText {
|
String get kategoriTindakanText {
|
||||||
if (kategoriTindakan == null) return 'Tidak Diketahui';
|
if (kategoriTindakan == null) return 'Tidak Diketahui';
|
||||||
|
@ -383,6 +383,9 @@ class JadwalPenyaluranController extends GetxController {
|
|||||||
required String lokasiPenyaluranId,
|
required String lokasiPenyaluranId,
|
||||||
required int jumlahPenerima,
|
required int jumlahPenerima,
|
||||||
required DateTime? tanggalPenyaluran,
|
required DateTime? tanggalPenyaluran,
|
||||||
|
required double jumlahDiterimaPerOrang,
|
||||||
|
required String stokBantuanId,
|
||||||
|
required double totalStokDibutuhkan,
|
||||||
}) async {
|
}) async {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
@ -427,6 +430,7 @@ class JadwalPenyaluranController extends GetxController {
|
|||||||
'stok_bantuan_id': skemaBantuanCache[skemaId]?.stokBantuanId,
|
'stok_bantuan_id': skemaBantuanCache[skemaId]?.stokBantuanId,
|
||||||
'status_penerimaan': 'BELUMMENERIMA',
|
'status_penerimaan': 'BELUMMENERIMA',
|
||||||
'qr_code_hash': qrCodeHash,
|
'qr_code_hash': qrCodeHash,
|
||||||
|
'jumlah_bantuan': jumlahDiterimaPerOrang,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Simpan data penerima ke database
|
// Simpan data penerima ke database
|
||||||
@ -435,6 +439,29 @@ class JadwalPenyaluranController extends GetxController {
|
|||||||
.insert(penerimaPenyaluran);
|
.insert(penerimaPenyaluran);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update stok bantuan (kurangi dengan total stok yang dibutuhkan)
|
||||||
|
try {
|
||||||
|
// Dapatkan stok saat ini
|
||||||
|
final stokData = await _supabaseService.client
|
||||||
|
.from('stok_bantuan')
|
||||||
|
.select('total_stok')
|
||||||
|
.eq('id', stokBantuanId)
|
||||||
|
.single();
|
||||||
|
|
||||||
|
if (stokData != null && stokData['total_stok'] != null) {
|
||||||
|
final currentStok = stokData['total_stok'].toDouble();
|
||||||
|
final newStok = currentStok - totalStokDibutuhkan;
|
||||||
|
|
||||||
|
// Update stok bantuan dengan nilai baru
|
||||||
|
await _supabaseService.client
|
||||||
|
.from('stok_bantuan')
|
||||||
|
.update({'total_stok': newStok}).eq('id', stokBantuanId);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Error updating stok bantuan: $e');
|
||||||
|
// Tidak throw exception di sini karena penyaluran sudah disimpan
|
||||||
|
}
|
||||||
|
|
||||||
// Setelah berhasil menambahkan, refresh data
|
// Setelah berhasil menambahkan, refresh data
|
||||||
await loadJadwalData();
|
await loadJadwalData();
|
||||||
await loadPermintaanPenjadwalanData();
|
await loadPermintaanPenjadwalanData();
|
||||||
|
@ -108,7 +108,6 @@ class PengaduanController extends GetxController {
|
|||||||
required String tindakan,
|
required String tindakan,
|
||||||
required String kategoriTindakan,
|
required String kategoriTindakan,
|
||||||
required String statusTindakan,
|
required String statusTindakan,
|
||||||
required String prioritas,
|
|
||||||
String? catatan,
|
String? catatan,
|
||||||
String? hasilTindakan,
|
String? hasilTindakan,
|
||||||
required List<String> buktiTindakanPaths,
|
required List<String> buktiTindakanPaths,
|
||||||
@ -134,7 +133,6 @@ class PengaduanController extends GetxController {
|
|||||||
'tindakan': tindakan,
|
'tindakan': tindakan,
|
||||||
'catatan': catatan,
|
'catatan': catatan,
|
||||||
'status_tindakan': statusTindakan,
|
'status_tindakan': statusTindakan,
|
||||||
'prioritas': prioritas,
|
|
||||||
'kategori_tindakan': kategoriTindakan,
|
'kategori_tindakan': kategoriTindakan,
|
||||||
'hasil_tindakan': hasilTindakan,
|
'hasil_tindakan': hasilTindakan,
|
||||||
'tanggal_tindakan': DateTime.now().toIso8601String(),
|
'tanggal_tindakan': DateTime.now().toIso8601String(),
|
||||||
@ -188,7 +186,6 @@ class PengaduanController extends GetxController {
|
|||||||
required String tindakan,
|
required String tindakan,
|
||||||
required String kategoriTindakan,
|
required String kategoriTindakan,
|
||||||
required String statusTindakan,
|
required String statusTindakan,
|
||||||
required String prioritas,
|
|
||||||
String? catatan,
|
String? catatan,
|
||||||
String? hasilTindakan,
|
String? hasilTindakan,
|
||||||
required List<String> buktiTindakanPaths,
|
required List<String> buktiTindakanPaths,
|
||||||
@ -217,7 +214,6 @@ class PengaduanController extends GetxController {
|
|||||||
'tindakan': tindakan,
|
'tindakan': tindakan,
|
||||||
'catatan': catatan,
|
'catatan': catatan,
|
||||||
'status_tindakan': statusTindakan,
|
'status_tindakan': statusTindakan,
|
||||||
'prioritas': prioritas,
|
|
||||||
'kategori_tindakan': kategoriTindakan,
|
'kategori_tindakan': kategoriTindakan,
|
||||||
'hasil_tindakan': hasilTindakan,
|
'hasil_tindakan': hasilTindakan,
|
||||||
'bukti_tindakan': buktiTindakanUrls,
|
'bukti_tindakan': buktiTindakanUrls,
|
||||||
|
@ -460,6 +460,92 @@ class DetailPengaduanView extends GetView<PengaduanController> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
if (pengaduan.fotoPengaduan != null &&
|
||||||
|
pengaduan.fotoPengaduan!.isNotEmpty)
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Foto Pengaduan:',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey.shade700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
SizedBox(
|
||||||
|
height: 120,
|
||||||
|
child: ListView.builder(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
itemCount: pengaduan.fotoPengaduan!.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
// Tampilkan gambar dalam ukuran penuh saat diklik
|
||||||
|
Get.to(() => Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Foto Pengaduan'),
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: InteractiveViewer(
|
||||||
|
child: Image.network(
|
||||||
|
pengaduan.fotoPengaduan![index],
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 120,
|
||||||
|
margin: const EdgeInsets.only(right: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(color: Colors.grey.shade300),
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: Image.network(
|
||||||
|
pengaduan.fotoPengaduan![index],
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
loadingBuilder:
|
||||||
|
(context, child, loadingProgress) {
|
||||||
|
if (loadingProgress == null) return child;
|
||||||
|
return Center(
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
value:
|
||||||
|
loadingProgress.expectedTotalBytes !=
|
||||||
|
null
|
||||||
|
? loadingProgress
|
||||||
|
.cumulativeBytesLoaded /
|
||||||
|
loadingProgress
|
||||||
|
.expectedTotalBytes!
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
errorBuilder: (context, error, stackTrace) {
|
||||||
|
return Container(
|
||||||
|
color: Colors.grey.shade200,
|
||||||
|
child: const Center(
|
||||||
|
child:
|
||||||
|
Icon(Icons.error, color: Colors.red),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
// Panel status pengaduan
|
// Panel status pengaduan
|
||||||
_buildStatusPanel(context, pengaduan),
|
_buildStatusPanel(context, pengaduan),
|
||||||
@ -1234,17 +1320,6 @@ class DetailPengaduanView extends GetView<PengaduanController> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
// Prioritas tindakan (jika ada)
|
|
||||||
if (tindakan.prioritas != null) ...[
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
// Menggunakan StatusPill untuk prioritas tindakan
|
|
||||||
StatusPill(
|
|
||||||
status: tindakan.prioritasText,
|
|
||||||
backgroundColor: _getPriorityColor(tindakan.prioritas),
|
|
||||||
textColor: Colors.white,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
// Tampilkan tombol edit jika status PROSES
|
// Tampilkan tombol edit jika status PROSES
|
||||||
if (tindakan.statusTindakan == 'PROSES') ...[
|
if (tindakan.statusTindakan == 'PROSES') ...[
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
@ -1288,24 +1363,10 @@ class DetailPengaduanView extends GetView<PengaduanController> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Color _getPriorityColor(String? priority) {
|
|
||||||
switch (priority) {
|
|
||||||
case 'TINGGI':
|
|
||||||
return Colors.red;
|
|
||||||
case 'SEDANG':
|
|
||||||
return Colors.orange;
|
|
||||||
case 'RENDAH':
|
|
||||||
return Colors.green;
|
|
||||||
default:
|
|
||||||
return Colors.grey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showTambahTindakanDialog(BuildContext context, String pengaduanId) {
|
void _showTambahTindakanDialog(BuildContext context, String pengaduanId) {
|
||||||
final formKey = GlobalKey<FormState>();
|
final formKey = GlobalKey<FormState>();
|
||||||
final tindakanController = TextEditingController();
|
final tindakanController = TextEditingController();
|
||||||
String? selectedKategori;
|
String? selectedKategori;
|
||||||
String? selectedPrioritas;
|
|
||||||
String selectedStatus = 'PROSES';
|
String selectedStatus = 'PROSES';
|
||||||
|
|
||||||
final List<String> kategoriOptions = [
|
final List<String> kategoriOptions = [
|
||||||
@ -1326,12 +1387,6 @@ class DetailPengaduanView extends GetView<PengaduanController> {
|
|||||||
'PELAPORAN_KE_PIHAK_BERWENANG',
|
'PELAPORAN_KE_PIHAK_BERWENANG',
|
||||||
];
|
];
|
||||||
|
|
||||||
final List<String> prioritasOptions = [
|
|
||||||
'RENDAH',
|
|
||||||
'SEDANG',
|
|
||||||
'TINGGI',
|
|
||||||
];
|
|
||||||
|
|
||||||
// Konversi ke format DropdownItem
|
// Konversi ke format DropdownItem
|
||||||
final List<DropdownItem<String>> kategoriItems = kategoriOptions
|
final List<DropdownItem<String>> kategoriItems = kategoriOptions
|
||||||
.map((kategori) => DropdownItem<String>(
|
.map((kategori) => DropdownItem<String>(
|
||||||
@ -1340,15 +1395,6 @@ class DetailPengaduanView extends GetView<PengaduanController> {
|
|||||||
))
|
))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
// Konversi ke format DropdownItem untuk prioritas
|
|
||||||
final List<DropdownItem<String>> prioritasItems = prioritasOptions
|
|
||||||
.map((prioritas) => DropdownItem<String>(
|
|
||||||
value: prioritas,
|
|
||||||
label: prioritas[0].toUpperCase() +
|
|
||||||
prioritas.substring(1).toLowerCase(),
|
|
||||||
))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (context) => AlertDialog(
|
||||||
@ -1380,26 +1426,6 @@ class DetailPengaduanView extends GetView<PengaduanController> {
|
|||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Prioritas menggunakan DropdownInput
|
|
||||||
DropdownInput<String>(
|
|
||||||
label: 'Prioritas',
|
|
||||||
hint: 'Pilih prioritas tindakan',
|
|
||||||
items: prioritasItems,
|
|
||||||
value: selectedPrioritas,
|
|
||||||
onChanged: (value) {
|
|
||||||
selectedPrioritas = value;
|
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Pilih prioritas tindakan';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
|
|
||||||
// Deskripsi tindakan menggunakan TextInput
|
// Deskripsi tindakan menggunakan TextInput
|
||||||
TextInput(
|
TextInput(
|
||||||
label: 'Deskripsi Tindakan',
|
label: 'Deskripsi Tindakan',
|
||||||
@ -1433,7 +1459,6 @@ class DetailPengaduanView extends GetView<PengaduanController> {
|
|||||||
tindakan: tindakanController.text,
|
tindakan: tindakanController.text,
|
||||||
kategoriTindakan: selectedKategori ?? '',
|
kategoriTindakan: selectedKategori ?? '',
|
||||||
statusTindakan: selectedStatus,
|
statusTindakan: selectedStatus,
|
||||||
prioritas: selectedPrioritas ?? '',
|
|
||||||
catatan: null,
|
catatan: null,
|
||||||
hasilTindakan: null,
|
hasilTindakan: null,
|
||||||
buktiTindakanPaths: [],
|
buktiTindakanPaths: [],
|
||||||
@ -1466,7 +1491,6 @@ class DetailPengaduanView extends GetView<PengaduanController> {
|
|||||||
final hasilTindakanController =
|
final hasilTindakanController =
|
||||||
TextEditingController(text: tindakan.hasilTindakan);
|
TextEditingController(text: tindakan.hasilTindakan);
|
||||||
String? selectedKategori = tindakan.kategoriTindakan;
|
String? selectedKategori = tindakan.kategoriTindakan;
|
||||||
String? selectedPrioritas = tindakan.prioritas;
|
|
||||||
String selectedStatus = 'SELESAI';
|
String selectedStatus = 'SELESAI';
|
||||||
|
|
||||||
// Gunakan List untuk bukti tindakan paths
|
// Gunakan List untuk bukti tindakan paths
|
||||||
@ -1865,8 +1889,6 @@ class DetailPengaduanView extends GetView<PengaduanController> {
|
|||||||
kategoriTindakan: selectedKategori ??
|
kategoriTindakan: selectedKategori ??
|
||||||
'', // Gunakan kategori yang sudah ada
|
'', // Gunakan kategori yang sudah ada
|
||||||
statusTindakan: selectedStatus,
|
statusTindakan: selectedStatus,
|
||||||
prioritas: selectedPrioritas ??
|
|
||||||
'', // Gunakan prioritas yang sudah ada
|
|
||||||
catatan: catatanController.text.isEmpty
|
catatan: catatanController.text.isEmpty
|
||||||
? null
|
? null
|
||||||
: catatanController.text,
|
: catatanController.text,
|
||||||
|
@ -37,7 +37,7 @@ class DetailPenyaluranPage extends StatelessWidget {
|
|||||||
title: const Text('Detail Penyaluran'),
|
title: const Text('Detail Penyaluran'),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
icon: const Icon(Icons.arrow_back, color: AppTheme.primaryColor),
|
||||||
onPressed: () => Get.back(),
|
onPressed: () => Get.back(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -969,8 +969,14 @@ class DetailPenyaluranPage extends StatelessWidget {
|
|||||||
backgroundColor: AppTheme.successColor,
|
backgroundColor: AppTheme.successColor,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
// Tombol disabled jika belum semua penerima menerima bantuan
|
||||||
|
disabledBackgroundColor: Colors.grey.shade300,
|
||||||
|
disabledForegroundColor: Colors.grey.shade700,
|
||||||
),
|
),
|
||||||
onPressed: controller.selesaikanPenyaluran,
|
onPressed: controller.penerimaPenyaluran.every((penerima) =>
|
||||||
|
penerima.statusPenerimaan?.toUpperCase() == 'DITERIMA')
|
||||||
|
? controller.selesaikanPenyaluran
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
|
@ -321,8 +321,6 @@ class PengaduanView extends GetView<PengaduanController> {
|
|||||||
String formattedDate = '';
|
String formattedDate = '';
|
||||||
if (item.tanggalPengaduan != null) {
|
if (item.tanggalPengaduan != null) {
|
||||||
formattedDate = DateTimeHelper.formatDate(item.tanggalPengaduan);
|
formattedDate = DateTimeHelper.formatDate(item.tanggalPengaduan);
|
||||||
} else if (item.createdAt != null) {
|
|
||||||
formattedDate = DateTimeHelper.formatDate(item.createdAt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
@ -452,7 +450,7 @@ class PengaduanView extends GetView<PengaduanController> {
|
|||||||
child: _buildItemDetail(
|
child: _buildItemDetail(
|
||||||
context,
|
context,
|
||||||
icon: Icons.calendar_today,
|
icon: Icons.calendar_today,
|
||||||
label: 'Tanggal',
|
label: 'Tanggal Pengaduan',
|
||||||
value: formattedDate,
|
value: formattedDate,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -631,7 +629,6 @@ class PengaduanView extends GetView<PengaduanController> {
|
|||||||
tindakan: controller.tindakanController.text,
|
tindakan: controller.tindakanController.text,
|
||||||
kategoriTindakan: 'VERIFIKASI_DATA',
|
kategoriTindakan: 'VERIFIKASI_DATA',
|
||||||
statusTindakan: 'PROSES',
|
statusTindakan: 'PROSES',
|
||||||
prioritas: 'SEDANG',
|
|
||||||
catatan: controller.catatanController.text.isEmpty
|
catatan: controller.catatanController.text.isEmpty
|
||||||
? null
|
? null
|
||||||
: controller.catatanController.text,
|
: controller.catatanController.text,
|
||||||
|
@ -1,657 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/pengaduan_controller.dart';
|
|
||||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
|
||||||
import 'package:penyaluran_app/app/utils/date_time_helper.dart';
|
|
||||||
|
|
||||||
class PengaduanView extends GetView<PengaduanController> {
|
|
||||||
const PengaduanView({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
// Ringkasan pengaduan
|
|
||||||
_buildPengaduanSummary(context),
|
|
||||||
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
|
|
||||||
// Filter dan pencarian
|
|
||||||
_buildFilterSearch(context),
|
|
||||||
|
|
||||||
// Informasi terakhir update
|
|
||||||
_buildLastUpdateInfo(context),
|
|
||||||
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
|
|
||||||
// Daftar pengaduan
|
|
||||||
_buildPengaduanList(context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tambahkan widget untuk menampilkan waktu terakhir update
|
|
||||||
Widget _buildLastUpdateInfo(BuildContext context) {
|
|
||||||
return Obx(() {
|
|
||||||
final lastUpdate = DateTime
|
|
||||||
.now(); // Gunakan waktu saat ini atau dari controller jika tersedia
|
|
||||||
final formattedDate = DateTimeHelper.formatDateTimeWithHour(lastUpdate);
|
|
||||||
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Icon(Icons.update, size: 16, color: Colors.grey[600]),
|
|
||||||
const SizedBox(width: 4),
|
|
||||||
Text(
|
|
||||||
'Data terupdate: $formattedDate',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.grey[600],
|
|
||||||
fontStyle: FontStyle.italic,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildPengaduanSummary(BuildContext context) {
|
|
||||||
return Obx(() {
|
|
||||||
return Container(
|
|
||||||
width: double.infinity,
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
gradient: AppTheme.primaryGradient,
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Ringkasan Pengaduan',
|
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: _buildSummaryItem(
|
|
||||||
context,
|
|
||||||
icon: Icons.pending_actions,
|
|
||||||
title: 'Diproses',
|
|
||||||
value: controller.jumlahDiproses.toString(),
|
|
||||||
color: Colors.orange,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: _buildSummaryItem(
|
|
||||||
context,
|
|
||||||
icon: Icons.engineering,
|
|
||||||
title: 'Tindakan',
|
|
||||||
value: controller.jumlahTindakan.toString(),
|
|
||||||
color: Colors.blue,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: _buildSummaryItem(
|
|
||||||
context,
|
|
||||||
icon: Icons.check_circle,
|
|
||||||
title: 'Selesai',
|
|
||||||
value: controller.jumlahSelesai.toString(),
|
|
||||||
color: Colors.green,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildSummaryItem(
|
|
||||||
BuildContext context, {
|
|
||||||
required IconData icon,
|
|
||||||
required String title,
|
|
||||||
required String value,
|
|
||||||
required Color color,
|
|
||||||
}) {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(10),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white.withOpacity(0.2),
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
icon,
|
|
||||||
color: Colors.white,
|
|
||||||
size: 24,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
value,
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
Text(
|
|
||||||
title,
|
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildFilterSearch(BuildContext context) {
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: TextField(
|
|
||||||
controller: controller.searchController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Cari pengaduan...',
|
|
||||||
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) {
|
|
||||||
// Implementasi pencarian
|
|
||||||
controller.refreshData();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.grey.shade100,
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: PopupMenuButton<int>(
|
|
||||||
icon: const Icon(Icons.filter_list),
|
|
||||||
tooltip: 'Filter',
|
|
||||||
onSelected: (index) {
|
|
||||||
controller.changeCategory(index);
|
|
||||||
},
|
|
||||||
itemBuilder: (context) => [
|
|
||||||
const PopupMenuItem(
|
|
||||||
value: 0,
|
|
||||||
child: Text('Semua'),
|
|
||||||
),
|
|
||||||
const PopupMenuItem(
|
|
||||||
value: 1,
|
|
||||||
child: Text('Diproses'),
|
|
||||||
),
|
|
||||||
const PopupMenuItem(
|
|
||||||
value: 2,
|
|
||||||
child: Text('Tindakan'),
|
|
||||||
),
|
|
||||||
const PopupMenuItem(
|
|
||||||
value: 3,
|
|
||||||
child: Text('Selesai'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildPengaduanList(BuildContext context) {
|
|
||||||
return Obx(() {
|
|
||||||
if (controller.isLoading.value) {
|
|
||||||
return const Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.all(20.0),
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final filteredPengaduan = controller.getFilteredPengaduan();
|
|
||||||
|
|
||||||
if (filteredPengaduan.isEmpty) {
|
|
||||||
return Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(20.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.inbox_outlined,
|
|
||||||
size: 80,
|
|
||||||
color: Colors.grey.shade400,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Text(
|
|
||||||
'Belum ada pengaduan',
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
||||||
color: Colors.grey.shade600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Daftar Pengaduan',
|
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'${DateTimeHelper.formatNumber(filteredPengaduan.length)} item',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.refresh),
|
|
||||||
onPressed: () => controller.refreshData(),
|
|
||||||
tooltip: 'Refresh',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
...filteredPengaduan
|
|
||||||
.map((item) => _buildPengaduanItem(context, item)),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildPengaduanItem(BuildContext context, dynamic item) {
|
|
||||||
Color statusColor;
|
|
||||||
IconData statusIcon;
|
|
||||||
|
|
||||||
switch (item.status?.toUpperCase()) {
|
|
||||||
case 'MENUNGGU':
|
|
||||||
statusColor = AppTheme.warningColor;
|
|
||||||
statusIcon = Icons.pending;
|
|
||||||
break;
|
|
||||||
case 'TINDAKAN':
|
|
||||||
statusColor = AppTheme.infoColor;
|
|
||||||
statusIcon = Icons.sync;
|
|
||||||
break;
|
|
||||||
case 'SELESAI':
|
|
||||||
statusColor = AppTheme.successColor;
|
|
||||||
statusIcon = Icons.check_circle;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
statusColor = Colors.grey;
|
|
||||||
statusIcon = Icons.help_outline;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format tanggal menggunakan DateTimeHelper
|
|
||||||
String formattedDate = '';
|
|
||||||
if (item.tanggalPengaduan != null) {
|
|
||||||
formattedDate = DateTimeHelper.formatDate(item.tanggalPengaduan);
|
|
||||||
} else if (item.createdAt != null) {
|
|
||||||
formattedDate = DateTimeHelper.formatDate(item.createdAt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
width: double.infinity,
|
|
||||||
margin: const EdgeInsets.only(bottom: 12),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.grey.withAlpha(26),
|
|
||||||
spreadRadius: 1,
|
|
||||||
blurRadius: 3,
|
|
||||||
offset: const Offset(0, 1),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
item.warga?['nama'] ?? item.judul ?? '',
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: statusColor.withOpacity(0.1),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
statusIcon,
|
|
||||||
size: 16,
|
|
||||||
color: statusColor,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 4),
|
|
||||||
Text(
|
|
||||||
item.status ?? '',
|
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
||||||
color: statusColor,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
_buildItemDetail(
|
|
||||||
context,
|
|
||||||
icon: Icons.person,
|
|
||||||
label: 'NIK',
|
|
||||||
value: item.warga?['nik'] ?? '',
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
if (item.penerimaPenyaluran != null) ...[
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: _buildItemDetail(
|
|
||||||
context,
|
|
||||||
icon: Icons.category,
|
|
||||||
label: 'Penyaluran',
|
|
||||||
value: item.namaPenyaluran ?? '',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: _buildItemDetail(
|
|
||||||
context,
|
|
||||||
icon: Icons.inventory,
|
|
||||||
label: 'Jenis',
|
|
||||||
value: item.jenisBantuan ?? '',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
_buildItemDetail(
|
|
||||||
context,
|
|
||||||
icon: Icons.shopping_bag,
|
|
||||||
label: 'Jumlah',
|
|
||||||
value: item.jumlahBantuan ?? '',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
item.deskripsi ?? '',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
maxLines: 2,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
_buildItemDetail(
|
|
||||||
context,
|
|
||||||
icon: Icons.calendar_today,
|
|
||||||
label: 'Tanggal',
|
|
||||||
value: formattedDate,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: _buildActionButtons(context, item),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildItemDetail(
|
|
||||||
BuildContext context, {
|
|
||||||
required IconData icon,
|
|
||||||
required String label,
|
|
||||||
required String value,
|
|
||||||
}) {
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
icon,
|
|
||||||
size: 16,
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 4),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
label,
|
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
value,
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> _buildActionButtons(BuildContext context, dynamic item) {
|
|
||||||
final status = item.status?.toUpperCase();
|
|
||||||
|
|
||||||
if (status == 'MENUNGGU') {
|
|
||||||
return [
|
|
||||||
TextButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
// Implementasi untuk memproses pengaduan
|
|
||||||
_showTindakanDialog(context, item);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.engineering, size: 18),
|
|
||||||
label: const Text('Tindakan'),
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
foregroundColor: Colors.blue,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
// Navigasi ke halaman detail pengaduan
|
|
||||||
Get.toNamed('/detail-pengaduan', arguments: {'id': item.id});
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.info_outline, size: 18),
|
|
||||||
label: const Text('Detail'),
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
foregroundColor: Colors.grey,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
} else if (status == 'TINDAKAN') {
|
|
||||||
return [
|
|
||||||
TextButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
// Implementasi untuk menyelesaikan pengaduan
|
|
||||||
_showSelesaikanDialog(context, item);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.check_circle, size: 18),
|
|
||||||
label: const Text('Selesaikan'),
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
foregroundColor: Colors.green,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
// Navigasi ke halaman detail pengaduan
|
|
||||||
Get.toNamed('/detail-pengaduan', arguments: {'id': item.id});
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.info_outline, size: 18),
|
|
||||||
label: const Text('Detail'),
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
foregroundColor: Colors.grey,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
return [
|
|
||||||
TextButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
// Navigasi ke halaman detail pengaduan
|
|
||||||
Get.toNamed('/detail-pengaduan', arguments: {'id': item.id});
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.info_outline, size: 18),
|
|
||||||
label: const Text('Detail'),
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
foregroundColor: Colors.grey,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showTindakanDialog(BuildContext context, dynamic item) {
|
|
||||||
controller.tindakanController.clear();
|
|
||||||
controller.catatanController.clear();
|
|
||||||
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text('Tindakan Pengaduan'),
|
|
||||||
content: Form(
|
|
||||||
key: controller.tindakanFormKey,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text('Pengaduan dari: ${item.warga?['nama'] ?? ''}'),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
TextFormField(
|
|
||||||
controller: controller.tindakanController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'Tindakan yang dilakukan',
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
maxLines: 3,
|
|
||||||
validator: controller.validateTindakan,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
TextFormField(
|
|
||||||
controller: controller.catatanController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'Catatan (opsional)',
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
maxLines: 2,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: const Text('Batal'),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
if (controller.tindakanFormKey.currentState!.validate()) {
|
|
||||||
Navigator.pop(context);
|
|
||||||
controller.tambahTindakanPengaduan(
|
|
||||||
pengaduanId: item.id!,
|
|
||||||
tindakan: controller.tindakanController.text,
|
|
||||||
kategoriTindakan: 'VERIFIKASI_DATA',
|
|
||||||
statusTindakan: 'PROSES',
|
|
||||||
prioritas: 'SEDANG',
|
|
||||||
catatan: controller.catatanController.text.isEmpty
|
|
||||||
? null
|
|
||||||
: controller.catatanController.text,
|
|
||||||
buktiTindakanPaths: [],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: const Text('Simpan'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showSelesaikanDialog(BuildContext context, dynamic item) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text('Selesaikan Pengaduan'),
|
|
||||||
content: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text('Pengaduan dari: ${item.warga?['nama'] ?? ''}'),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
const Text(
|
|
||||||
'Apakah Anda yakin ingin menyelesaikan pengaduan ini?',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: const Text('Batal'),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
controller.selesaikanPengaduan(item.id!);
|
|
||||||
},
|
|
||||||
child: const Text('Selesaikan'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -34,6 +34,13 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
|||||||
final Rx<SkemaBantuanModel?> selectedSkemaBantuan =
|
final Rx<SkemaBantuanModel?> selectedSkemaBantuan =
|
||||||
Rx<SkemaBantuanModel?>(null);
|
Rx<SkemaBantuanModel?>(null);
|
||||||
final RxInt jumlahPenerima = 0.obs;
|
final RxInt jumlahPenerima = 0.obs;
|
||||||
|
final RxDouble jumlahDiterimaPerOrang = 0.0.obs;
|
||||||
|
final RxString namaStokBantuan = ''.obs;
|
||||||
|
final RxString satuanStokBantuan = ''.obs;
|
||||||
|
final RxDouble totalStokDibutuhkan = 0.0.obs;
|
||||||
|
final RxDouble totalStokTersedia = 0.0.obs;
|
||||||
|
final RxBool isStokCukup = false.obs;
|
||||||
|
final RxBool isUang = false.obs;
|
||||||
|
|
||||||
// Tanggal dan waktu penyaluran
|
// Tanggal dan waktu penyaluran
|
||||||
final Rx<DateTime?> selectedDate = Rx<DateTime?>(null);
|
final Rx<DateTime?> selectedDate = Rx<DateTime?>(null);
|
||||||
@ -50,11 +57,72 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
|||||||
print('pengajuan $pengajuanData');
|
print('pengajuan $pengajuanData');
|
||||||
|
|
||||||
jumlahPenerima.value = pengajuanData.length;
|
jumlahPenerima.value = pengajuanData.length;
|
||||||
|
|
||||||
|
// Hitung total stok yang dibutuhkan
|
||||||
|
totalStokDibutuhkan.value =
|
||||||
|
jumlahPenerima.value * jumlahDiterimaPerOrang.value;
|
||||||
|
|
||||||
|
// Perbarui status kecukupan stok
|
||||||
|
isStokCukup.value =
|
||||||
|
totalStokTersedia.value >= totalStokDibutuhkan.value;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading pengajuan kelayakan: $e');
|
print('Error loading pengajuan kelayakan: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fungsi untuk memuat informasi stok bantuan
|
||||||
|
Future<void> loadStokBantuanInfo(String stokBantuanId) async {
|
||||||
|
try {
|
||||||
|
if (stokBantuanId.isEmpty) {
|
||||||
|
namaStokBantuan.value = 'Tidak ada stok terkait';
|
||||||
|
satuanStokBantuan.value = '';
|
||||||
|
totalStokTersedia.value = 0;
|
||||||
|
isStokCukup.value = false;
|
||||||
|
isUang.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final stokData = await controller.supabaseService.client
|
||||||
|
.from('stok_bantuan')
|
||||||
|
.select('*')
|
||||||
|
.eq('id', stokBantuanId)
|
||||||
|
.single();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
} else {
|
||||||
|
namaStokBantuan.value = 'Stok tidak ditemukan';
|
||||||
|
satuanStokBantuan.value = '';
|
||||||
|
totalStokTersedia.value = 0;
|
||||||
|
isStokCukup.value = false;
|
||||||
|
isUang.value = false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Error loading stok bantuan: $e');
|
||||||
|
namaStokBantuan.value = 'Error memuat data stok';
|
||||||
|
satuanStokBantuan.value = '';
|
||||||
|
totalStokTersedia.value = 0;
|
||||||
|
isStokCukup.value = false;
|
||||||
|
isUang.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Form(
|
child: Form(
|
||||||
@ -72,33 +140,6 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
// Nama Penyaluran
|
|
||||||
Text(
|
|
||||||
'Nama Penyaluran',
|
|
||||||
style: Theme.of(context).textTheme.titleSmall,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
TextFormField(
|
|
||||||
controller: namaController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Masukkan nama penyaluran',
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 12,
|
|
||||||
vertical: 8,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Nama penyaluran tidak boleh kosong';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
|
|
||||||
// Skema Bantuan
|
// Skema Bantuan
|
||||||
Text(
|
Text(
|
||||||
'Skema Bantuan',
|
'Skema Bantuan',
|
||||||
@ -128,6 +169,20 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
|||||||
if (value != null) {
|
if (value != null) {
|
||||||
selectedSkemaBantuan.value =
|
selectedSkemaBantuan.value =
|
||||||
controller.skemaBantuanCache[value];
|
controller.skemaBantuanCache[value];
|
||||||
|
|
||||||
|
// Set jumlah yang diterima per orang
|
||||||
|
jumlahDiterimaPerOrang.value = selectedSkemaBantuan
|
||||||
|
.value?.jumlahDiterimaPerOrang ??
|
||||||
|
0.0;
|
||||||
|
|
||||||
|
// Load stok bantuan info
|
||||||
|
if (selectedSkemaBantuan.value?.stokBantuanId != null) {
|
||||||
|
await loadStokBantuanInfo(
|
||||||
|
selectedSkemaBantuan.value!.stokBantuanId!);
|
||||||
|
} else {
|
||||||
|
namaStokBantuan.value = 'Tidak ada stok terkait';
|
||||||
|
}
|
||||||
|
|
||||||
await loadPengajuanKelayakan(value);
|
await loadPengajuanKelayakan(value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -139,6 +194,405 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
|||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
// Jumlah Penerima (Otomatis)
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Jumlah Penerima',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Tooltip(
|
||||||
|
message:
|
||||||
|
'Jumlah penerima dari pengajuan kelayakan yang terverifikasi.',
|
||||||
|
triggerMode: TooltipTriggerMode.tap,
|
||||||
|
child: Icon(
|
||||||
|
Icons.info_outline,
|
||||||
|
size: 16,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Obx(() => TextFormField(
|
||||||
|
readOnly: true,
|
||||||
|
controller: TextEditingController(
|
||||||
|
text: jumlahPenerima.value.toString()),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText:
|
||||||
|
'Jumlah penerima akan diambil otomatis',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// Jumlah Diterima Per Orang (dari skema)
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Jumlah Per Penerima',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Tooltip(
|
||||||
|
message:
|
||||||
|
'Jumlah yang akan diterima setiap penerima bantuan.',
|
||||||
|
triggerMode: TooltipTriggerMode.tap,
|
||||||
|
child: Icon(
|
||||||
|
Icons.info_outline,
|
||||||
|
size: 16,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Obx(() => TextFormField(
|
||||||
|
readOnly: true,
|
||||||
|
controller: TextEditingController(
|
||||||
|
text:
|
||||||
|
jumlahDiterimaPerOrang.value.toString()),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText:
|
||||||
|
'Jumlah diterima per orang dari skema bantuan',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
|
suffixText: satuanStokBantuan.value.isNotEmpty
|
||||||
|
? satuanStokBantuan.value
|
||||||
|
: 'satuan',
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
'Daftar Penerima',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Obx(() => OutlinedButton.icon(
|
||||||
|
onPressed: jumlahPenerima.value > 0
|
||||||
|
? () async {
|
||||||
|
final pengajuanData = await controller
|
||||||
|
.supabaseService.client
|
||||||
|
.from('xx02_pengajuan_kelayakan_bantuan')
|
||||||
|
.select('*, warga:warga_id(*)')
|
||||||
|
.eq('skema_bantuan_id',
|
||||||
|
selectedSkemaBantuanId.value ?? '')
|
||||||
|
.eq('status', 'TERVERIFIKASI');
|
||||||
|
|
||||||
|
Get.dialog(
|
||||||
|
Dialog(
|
||||||
|
child: Container(
|
||||||
|
width:
|
||||||
|
MediaQuery.of(context).size.width * 0.9,
|
||||||
|
height:
|
||||||
|
MediaQuery.of(context).size.height * 0.8,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Daftar Penerima Bantuan',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => Get.back(),
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: DataTable(
|
||||||
|
columnSpacing: 20,
|
||||||
|
horizontalMargin: 20,
|
||||||
|
columns: const [
|
||||||
|
DataColumn(label: Text('No')),
|
||||||
|
DataColumn(label: Text('Nama')),
|
||||||
|
DataColumn(label: Text('NIK')),
|
||||||
|
DataColumn(
|
||||||
|
label: Text('Alamat')),
|
||||||
|
],
|
||||||
|
rows: pengajuanData
|
||||||
|
.asMap()
|
||||||
|
.entries
|
||||||
|
.map((entry) {
|
||||||
|
final warga =
|
||||||
|
entry.value['warga'];
|
||||||
|
return DataRow(
|
||||||
|
cells: [
|
||||||
|
DataCell(Text(
|
||||||
|
'${entry.key + 1}')),
|
||||||
|
DataCell(Text(
|
||||||
|
warga['nama_lengkap'] ??
|
||||||
|
'-')),
|
||||||
|
DataCell(Text(
|
||||||
|
warga['nik'] ?? '-')),
|
||||||
|
DataCell(Text(
|
||||||
|
warga['alamat'] ??
|
||||||
|
'-')),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.people),
|
||||||
|
label: const Text('Lihat Daftar'),
|
||||||
|
style: ButtonStyle(
|
||||||
|
foregroundColor:
|
||||||
|
WidgetStateProperty.resolveWith<Color>((states) {
|
||||||
|
return jumlahPenerima.value <= 0
|
||||||
|
? Colors.grey
|
||||||
|
: Theme.of(context).primaryColor;
|
||||||
|
}),
|
||||||
|
backgroundColor:
|
||||||
|
WidgetStateProperty.resolveWith<Color>((states) {
|
||||||
|
return jumlahPenerima.value <= 0
|
||||||
|
? Colors.grey.withOpacity(0.1)
|
||||||
|
: Theme.of(context).primaryColor.withOpacity(0.1);
|
||||||
|
}),
|
||||||
|
padding: WidgetStateProperty.all<EdgeInsets>(
|
||||||
|
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
|
),
|
||||||
|
shape: WidgetStateProperty.all<RoundedRectangleBorder>(
|
||||||
|
RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
side: BorderSide(
|
||||||
|
color: jumlahPenerima.value <= 0
|
||||||
|
? Colors.grey.withOpacity(0.5)
|
||||||
|
: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
// Informasi Stok Bantuan
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.amber[50],
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(color: Colors.amber[200]!),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Informasi Stok Bantuan',
|
||||||
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.amber[800],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text('Nama Stok'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Obx(() => Text(
|
||||||
|
namaStokBantuan.value,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text('Satuan Stok'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Obx(() => Text(
|
||||||
|
satuanStokBantuan.value,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text('Total Stok Tersedia'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Obx(() => Text(
|
||||||
|
isUang.value
|
||||||
|
? 'Rp ${DateTimeHelper.formatNumber(totalStokTersedia.value)}'
|
||||||
|
: '${totalStokTersedia.value} ${satuanStokBantuan.value}',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Text('Total Stok Dibutuhkan'),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Tooltip(
|
||||||
|
message:
|
||||||
|
'Total stok yang dibutuhkan dihitung dari jumlah penerima × jumlah yang diterima per orang',
|
||||||
|
triggerMode: TooltipTriggerMode.tap,
|
||||||
|
child: const Icon(Icons.info_outline,
|
||||||
|
size: 16),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Obx(() => Text(
|
||||||
|
isUang.value
|
||||||
|
? 'Rp ${DateTimeHelper.formatNumber(totalStokDibutuhkan.value)}'
|
||||||
|
: '${totalStokDibutuhkan.value} ${satuanStokBantuan.value}',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Obx(() => selectedSkemaBantuanId.value != null
|
||||||
|
? Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 6, horizontal: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isStokCukup.value
|
||||||
|
? Colors.green.withOpacity(0.1)
|
||||||
|
: Colors.red.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
border: Border.all(
|
||||||
|
color: isStokCukup.value
|
||||||
|
? Colors.green
|
||||||
|
: Colors.red,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
isStokCukup.value
|
||||||
|
? Icons.check_circle
|
||||||
|
: Icons.error,
|
||||||
|
color: isStokCukup.value
|
||||||
|
? Colors.green
|
||||||
|
: Colors.red,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
isStokCukup.value
|
||||||
|
? 'Stok tersedia cukup untuk penyaluran'
|
||||||
|
: 'Stok tidak cukup untuk penyaluran! Tambah stok terlebih dahulu.',
|
||||||
|
style: TextStyle(
|
||||||
|
color: isStokCukup.value
|
||||||
|
? Colors.green[800]
|
||||||
|
: Colors.red[800],
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
// Nama Penyaluran
|
||||||
|
Text(
|
||||||
|
'Judul Penyaluran',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
TextFormField(
|
||||||
|
controller: namaController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Masukkan judul penyaluran',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return 'Judul penyaluran tidak boleh kosong';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Lokasi Penyaluran
|
// Lokasi Penyaluran
|
||||||
Text(
|
Text(
|
||||||
@ -176,129 +630,26 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
|||||||
)),
|
)),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Jumlah Penerima (Otomatis)
|
|
||||||
Text(
|
|
||||||
'Jumlah Penerima',
|
|
||||||
style: Theme.of(context).textTheme.titleSmall,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Obx(() => TextFormField(
|
|
||||||
readOnly: true,
|
|
||||||
controller: TextEditingController(
|
|
||||||
text: jumlahPenerima.value.toString()),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Jumlah penerima akan diambil otomatis',
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 12,
|
|
||||||
vertical: 8,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
'Info: Jumlah penerima diambil dari data pengajuan kelayakan bantuan yang telah terverifikasi untuk skema bantuan yang dipilih.',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.grey[600],
|
|
||||||
fontStyle: FontStyle.italic,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Obx(() => jumlahPenerima.value > 0
|
|
||||||
? TextButton.icon(
|
|
||||||
onPressed: () async {
|
|
||||||
final pengajuanData = await controller
|
|
||||||
.supabaseService.client
|
|
||||||
.from('xx02_pengajuan_kelayakan_bantuan')
|
|
||||||
.select('*, warga:warga_id(*)')
|
|
||||||
.eq('skema_bantuan_id',
|
|
||||||
selectedSkemaBantuanId.value ?? '')
|
|
||||||
.eq('status', 'TERVERIFIKASI');
|
|
||||||
|
|
||||||
Get.dialog(
|
|
||||||
Dialog(
|
|
||||||
child: Container(
|
|
||||||
width: MediaQuery.of(context).size.width * 0.9,
|
|
||||||
height: MediaQuery.of(context).size.height * 0.8,
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
const Text(
|
|
||||||
'Daftar Penerima Bantuan',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
onPressed: () => Get.back(),
|
|
||||||
icon: const Icon(Icons.close),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Expanded(
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
child: DataTable(
|
|
||||||
columnSpacing: 20,
|
|
||||||
horizontalMargin: 20,
|
|
||||||
columns: const [
|
|
||||||
DataColumn(label: Text('No')),
|
|
||||||
DataColumn(label: Text('Nama')),
|
|
||||||
DataColumn(label: Text('NIK')),
|
|
||||||
DataColumn(label: Text('Alamat')),
|
|
||||||
],
|
|
||||||
rows: pengajuanData
|
|
||||||
.asMap()
|
|
||||||
.entries
|
|
||||||
.map((entry) {
|
|
||||||
final warga = entry.value['warga'];
|
|
||||||
return DataRow(
|
|
||||||
cells: [
|
|
||||||
DataCell(
|
|
||||||
Text('${entry.key + 1}')),
|
|
||||||
DataCell(Text(
|
|
||||||
warga['nama_lengkap'] ??
|
|
||||||
'-')),
|
|
||||||
DataCell(
|
|
||||||
Text(warga['nik'] ?? '-')),
|
|
||||||
DataCell(Text(
|
|
||||||
warga['alamat'] ?? '-')),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.people),
|
|
||||||
label: const Text('Lihat Daftar Penerima'),
|
|
||||||
)
|
|
||||||
: const SizedBox.shrink()),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
|
|
||||||
// Tanggal Penyaluran
|
// Tanggal Penyaluran
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Tanggal Penyaluran',
|
'Tanggal Penyaluran',
|
||||||
style: Theme.of(context).textTheme.titleSmall,
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
),
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Tooltip(
|
||||||
|
message:
|
||||||
|
'Tanggal pelaksanaan minimal 1 hari sebelum dijadwalkan',
|
||||||
|
triggerMode: TooltipTriggerMode.tap,
|
||||||
|
child: Icon(
|
||||||
|
Icons.info_outline,
|
||||||
|
size: 16,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: tanggalPenyaluranController,
|
controller: tanggalPenyaluranController,
|
||||||
@ -337,36 +688,7 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
|||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
|
||||||
|
|
||||||
// Hint info tanggal minimal
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.blue[50],
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
border: Border.all(color: Colors.blue[200]!),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(
|
|
||||||
Icons.info_outline,
|
|
||||||
color: Colors.blue,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
'Tanggal pelaksanaan minimal 1 hari sebelum dijadwalkan',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.blue[900],
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Waktu Mulai
|
// Waktu Mulai
|
||||||
@ -445,6 +767,19 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
|||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (formKey.currentState!.validate()) {
|
if (formKey.currentState!.validate()) {
|
||||||
|
// Periksa kecukupan stok
|
||||||
|
if (!isStokCukup.value) {
|
||||||
|
Get.snackbar(
|
||||||
|
'Stok Tidak Cukup',
|
||||||
|
'Stok bantuan tidak mencukupi untuk penyaluran ini. Silakan tambah stok terlebih dahulu.',
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
colorText: Colors.white,
|
||||||
|
duration: const Duration(seconds: 4),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Gabungkan tanggal dan waktu mulai
|
// Gabungkan tanggal dan waktu mulai
|
||||||
DateTime? tanggalWaktuMulai;
|
DateTime? tanggalWaktuMulai;
|
||||||
if (selectedDate.value != null &&
|
if (selectedDate.value != null &&
|
||||||
@ -468,7 +803,10 @@ class TambahPenyaluranView extends GetView<JadwalPenyaluranController> {
|
|||||||
tanggalPenyaluran: tanggalWaktuMulai,
|
tanggalPenyaluran: tanggalWaktuMulai,
|
||||||
kategoriBantuanId:
|
kategoriBantuanId:
|
||||||
selectedSkemaBantuan.value!.kategoriBantuanId!,
|
selectedSkemaBantuan.value!.kategoriBantuanId!,
|
||||||
);
|
jumlahDiterimaPerOrang: jumlahDiterimaPerOrang.value,
|
||||||
|
stokBantuanId:
|
||||||
|
selectedSkemaBantuan.value!.stokBantuanId!,
|
||||||
|
totalStokDibutuhkan: totalStokDibutuhkan.value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
|
@ -110,33 +110,37 @@ class WargaDashboardController extends GetxController {
|
|||||||
),
|
),
|
||||||
penyaluran_bantuan:penyaluran_bantuan_id(
|
penyaluran_bantuan:penyaluran_bantuan_id(
|
||||||
*,
|
*,
|
||||||
lokasi_penyaluran(*)
|
lokasi_penyaluran(*),
|
||||||
|
kategori_bantuan(*)
|
||||||
)
|
)
|
||||||
''').eq('warga_id', wargaId).order('created_at', ascending: false);
|
''').eq('warga_id', wargaId).order('created_at', ascending: false);
|
||||||
|
|
||||||
final List<PenerimaPenyaluranModel> penerima = [];
|
final List<PenerimaPenyaluranModel> penerima = [];
|
||||||
|
|
||||||
|
// Loop melalui setiap data penerima
|
||||||
for (var item in response) {
|
for (var item in response) {
|
||||||
|
// Pastikan data penerima sesuai dengan tipe data yang diharapkan
|
||||||
Map<String, dynamic> sanitizedPenerimaData =
|
Map<String, dynamic> sanitizedPenerimaData =
|
||||||
Map<String, dynamic>.from(item);
|
Map<String, dynamic>.from(item);
|
||||||
|
|
||||||
|
// Konversi jumlah_bantuan ke double jika bertipe String
|
||||||
if (sanitizedPenerimaData['jumlah_bantuan'] is String) {
|
if (sanitizedPenerimaData['jumlah_bantuan'] is String) {
|
||||||
var jumlahBantuan = double.tryParse(
|
sanitizedPenerimaData['jumlah_bantuan'] =
|
||||||
sanitizedPenerimaData['jumlah_bantuan'] as String);
|
double.tryParse(sanitizedPenerimaData['jumlah_bantuan']) ?? 0.0;
|
||||||
sanitizedPenerimaData['jumlah_bantuan'] = jumlahBantuan;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tambahkan informasi apakah bantuan uang atau bukan dan satuan
|
// Ambil data dari stok bantuan jika tersedia
|
||||||
if (sanitizedPenerimaData['stok_bantuan'] != null) {
|
if (sanitizedPenerimaData['stok_bantuan'] != null) {
|
||||||
// Cek apakah bantuan uang
|
// Cek apakah bantuan berupa uang atau barang
|
||||||
final isUang =
|
final isUang =
|
||||||
sanitizedPenerimaData['stok_bantuan']['is_uang'] ?? false;
|
sanitizedPenerimaData['stok_bantuan']['is_uang'] ?? false;
|
||||||
sanitizedPenerimaData['is_uang'] = isUang;
|
sanitizedPenerimaData['is_uang'] = isUang;
|
||||||
|
|
||||||
// Ambil satuan
|
// Ambil satuan bantuan
|
||||||
final satuan = sanitizedPenerimaData['stok_bantuan']['satuan'] ?? '';
|
final satuan = sanitizedPenerimaData['stok_bantuan']['satuan'] ?? '';
|
||||||
sanitizedPenerimaData['satuan'] = satuan;
|
sanitizedPenerimaData['satuan'] = satuan;
|
||||||
|
|
||||||
// Ambil nama kategori bantuan jika tersedia
|
// Ambil nama kategori bantuan
|
||||||
if (sanitizedPenerimaData['stok_bantuan']['kategori_bantuan'] !=
|
if (sanitizedPenerimaData['stok_bantuan']['kategori_bantuan'] !=
|
||||||
null) {
|
null) {
|
||||||
final kategoriNama = sanitizedPenerimaData['stok_bantuan']
|
final kategoriNama = sanitizedPenerimaData['stok_bantuan']
|
||||||
@ -146,7 +150,7 @@ class WargaDashboardController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tambahkan informasi dari penyaluran bantuan
|
// Ambil data dari penyaluran bantuan jika tersedia
|
||||||
if (sanitizedPenerimaData['penyaluran_bantuan'] != null) {
|
if (sanitizedPenerimaData['penyaluran_bantuan'] != null) {
|
||||||
// Ambil nama penyaluran
|
// Ambil nama penyaluran
|
||||||
final namaPenyaluran =
|
final namaPenyaluran =
|
||||||
@ -158,6 +162,11 @@ class WargaDashboardController extends GetxController {
|
|||||||
sanitizedPenerimaData['penyaluran_bantuan']['deskripsi'] ?? '';
|
sanitizedPenerimaData['penyaluran_bantuan']['deskripsi'] ?? '';
|
||||||
sanitizedPenerimaData['deskripsi_penyaluran'] = deskripsiPenyaluran;
|
sanitizedPenerimaData['deskripsi_penyaluran'] = deskripsiPenyaluran;
|
||||||
|
|
||||||
|
// Ambil status penyaluran
|
||||||
|
final statusPenyaluran =
|
||||||
|
sanitizedPenerimaData['penyaluran_bantuan']['status'] ?? '';
|
||||||
|
sanitizedPenerimaData['status_penyaluran'] = statusPenyaluran;
|
||||||
|
|
||||||
// Ambil lokasi penyaluran jika tersedia
|
// Ambil lokasi penyaluran jika tersedia
|
||||||
if (sanitizedPenerimaData['penyaluran_bantuan']
|
if (sanitizedPenerimaData['penyaluran_bantuan']
|
||||||
['lokasi_penyaluran'] !=
|
['lokasi_penyaluran'] !=
|
||||||
@ -172,6 +181,19 @@ class WargaDashboardController extends GetxController {
|
|||||||
'';
|
'';
|
||||||
sanitizedPenerimaData['lokasi_penyaluran_alamat'] = lokasiAlamat;
|
sanitizedPenerimaData['lokasi_penyaluran_alamat'] = lokasiAlamat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ambil kategori bantuan dari relasi langsung jika ada
|
||||||
|
if (sanitizedPenerimaData['penyaluran_bantuan']['kategori_bantuan'] !=
|
||||||
|
null) {
|
||||||
|
final kategoriNama = sanitizedPenerimaData['penyaluran_bantuan']
|
||||||
|
['kategori_bantuan']['nama'] ??
|
||||||
|
'';
|
||||||
|
// Jika belum ada kategori_nama dari stok_bantuan, gunakan dari relasi langsung
|
||||||
|
if (sanitizedPenerimaData['kategori_nama'] == null ||
|
||||||
|
sanitizedPenerimaData['kategori_nama'].isEmpty) {
|
||||||
|
sanitizedPenerimaData['kategori_nama'] = kategoriNama;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var model = PenerimaPenyaluranModel.fromJson(sanitizedPenerimaData);
|
var model = PenerimaPenyaluranModel.fromJson(sanitizedPenerimaData);
|
||||||
@ -396,4 +418,74 @@ class WargaDashboardController extends GetxController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Metode untuk menambahkan pengaduan baru
|
||||||
|
Future<bool> addPengaduan({
|
||||||
|
required String judul,
|
||||||
|
required String deskripsi,
|
||||||
|
required String penerimaPenyaluranId,
|
||||||
|
List<String> fotoPengaduanPaths = const [],
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
isLoading.value = true;
|
||||||
|
|
||||||
|
// Cari warga_id berdasarkan user_id
|
||||||
|
final wargaData = await _supabaseService.getWargaByUserId();
|
||||||
|
if (wargaData == null) {
|
||||||
|
throw Exception('Data warga tidak ditemukan');
|
||||||
|
}
|
||||||
|
|
||||||
|
final String wargaId = wargaData['id'];
|
||||||
|
|
||||||
|
// Upload foto pengaduan jika ada
|
||||||
|
List<String> fotoPengaduanUrls = [];
|
||||||
|
if (fotoPengaduanPaths.isNotEmpty) {
|
||||||
|
fotoPengaduanUrls = await _supabaseService.uploadMultipleFiles(
|
||||||
|
fotoPengaduanPaths, 'pengaduan', 'foto_pengaduan') ??
|
||||||
|
[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buat objek pengaduan
|
||||||
|
final Map<String, dynamic> pengaduanData = {
|
||||||
|
'judul': judul,
|
||||||
|
'deskripsi': deskripsi,
|
||||||
|
'status': 'MENUNGGU',
|
||||||
|
'warga_id': wargaId,
|
||||||
|
'penerima_penyaluran_id': penerimaPenyaluranId,
|
||||||
|
'foto_pengaduan': fotoPengaduanUrls,
|
||||||
|
'tanggal_pengaduan': DateTime.now().toIso8601String(),
|
||||||
|
'created_at': DateTime.now().toIso8601String(),
|
||||||
|
'updated_at': DateTime.now().toIso8601String(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simpan pengaduan ke Supabase
|
||||||
|
await _supabaseService.client.from('pengaduan').insert(pengaduanData);
|
||||||
|
|
||||||
|
// Refresh data pengaduan
|
||||||
|
await fetchPengaduan();
|
||||||
|
|
||||||
|
Get.snackbar(
|
||||||
|
'Berhasil',
|
||||||
|
'Pengaduan berhasil dibuat dan akan segera diproses',
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
colorText: Colors.white,
|
||||||
|
duration: const Duration(seconds: 3),
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
print('Error membuat pengaduan: $e');
|
||||||
|
Get.snackbar(
|
||||||
|
'Error',
|
||||||
|
'Gagal membuat pengaduan: ${e.toString()}',
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
colorText: Colors.white,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -916,36 +916,12 @@ class WargaDetailPengaduanView extends GetView<WargaDashboardController> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
// Prioritas tindakan (jika ada)
|
|
||||||
if (tindakan.prioritas != null) ...[
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
// Menggunakan StatusPill untuk prioritas tindakan
|
|
||||||
StatusPill(
|
|
||||||
status: tindakan.prioritasText,
|
|
||||||
backgroundColor: _getPriorityColor(tindakan.prioritas),
|
|
||||||
textColor: Colors.white,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Color _getPriorityColor(String? priority) {
|
|
||||||
switch (priority) {
|
|
||||||
case 'TINGGI':
|
|
||||||
return Colors.red;
|
|
||||||
case 'SEDANG':
|
|
||||||
return Colors.orange;
|
|
||||||
case 'RENDAH':
|
|
||||||
return Colors.green;
|
|
||||||
default:
|
|
||||||
return Colors.grey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void showFullScreenImage(BuildContext context, String imageUrl) {
|
void showFullScreenImage(BuildContext context, String imageUrl) {
|
||||||
// Buat controller untuk InteractiveViewer
|
// Buat controller untuk InteractiveViewer
|
||||||
final TransformationController transformationController =
|
final TransformationController transformationController =
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart';
|
import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart';
|
||||||
import 'package:penyaluran_app/app/widgets/bantuan_card.dart';
|
import 'package:penyaluran_app/app/widgets/bantuan_card.dart';
|
||||||
|
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||||
|
|
||||||
class WargaPenerimaanView extends GetView<WargaDashboardController> {
|
class WargaPenerimaanView extends GetView<WargaDashboardController> {
|
||||||
const WargaPenerimaanView({super.key});
|
const WargaPenerimaanView({super.key});
|
||||||
@ -23,15 +24,6 @@ class WargaPenerimaanView extends GetView<WargaDashboardController> {
|
|||||||
: _buildPenerimaanList(),
|
: _buildPenerimaanList(),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: () {
|
|
||||||
// Navigasi ke halaman riwayat penerimaan
|
|
||||||
Get.toNamed('/riwayat-penyaluran');
|
|
||||||
},
|
|
||||||
backgroundColor: Colors.blue,
|
|
||||||
tooltip: 'Riwayat Penerimaan',
|
|
||||||
child: const Icon(Icons.history),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,13 +35,13 @@ class WargaPenerimaanView extends GetView<WargaDashboardController> {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.blue.withOpacity(0.1),
|
color: AppTheme.primaryColor.withOpacity(0.1),
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.volunteer_activism,
|
Icons.volunteer_activism,
|
||||||
size: 80,
|
size: 80,
|
||||||
color: Colors.blue.shade400,
|
color: AppTheme.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
@ -82,6 +74,8 @@ class WargaPenerimaanView extends GetView<WargaDashboardController> {
|
|||||||
label: const Text('Muat Ulang'),
|
label: const Text('Muat Ulang'),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||||
|
backgroundColor: AppTheme.primaryColor,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
|
@ -30,13 +30,13 @@ class WargaPengaduanView extends GetView<WargaDashboardController> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
Icons.report_problem,
|
Icons.check_circle_outline,
|
||||||
size: 80,
|
size: 80,
|
||||||
color: Colors.grey.shade400,
|
color: Colors.grey.shade400,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
'Belum Ada Pengaduan',
|
'Bagus!',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -45,27 +45,12 @@ class WargaPengaduanView extends GetView<WargaDashboardController> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'Anda belum membuat pengaduan',
|
'Belum ada pengaduan yang dibuat',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Colors.grey.shade600,
|
color: Colors.grey.shade600,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
|
||||||
ElevatedButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
// TODO: Implementasi navigasi ke halaman buat pengaduan
|
|
||||||
Get.toNamed('/buat-pengaduan');
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.add),
|
|
||||||
label: const Text('Buat Pengaduan Baru'),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 24,
|
|
||||||
vertical: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -108,16 +108,6 @@ class WargaView extends GetView<WargaDashboardController> {
|
|||||||
badgeColor: Colors.orange,
|
badgeColor: Colors.orange,
|
||||||
onTap: () => controller.changeTab(2),
|
onTap: () => controller.changeTab(2),
|
||||||
),
|
),
|
||||||
DrawerMenuItem(
|
|
||||||
icon: Icons.assignment_outlined,
|
|
||||||
title: 'Pengajuan Kelayakan',
|
|
||||||
onTap: () {
|
|
||||||
// TODO: Navigasi ke halaman pengajuan kelayakan
|
|
||||||
Get.toNamed('/pengajuan-kelayakan');
|
|
||||||
},
|
|
||||||
badgeCount: controller.totalPengajuanMenunggu.value,
|
|
||||||
badgeColor: Colors.blue,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
body: Obx(() {
|
body: Obx(() {
|
||||||
@ -161,20 +151,6 @@ class WargaView extends GetView<WargaDashboardController> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
floatingActionButton: Obx(() {
|
|
||||||
// Tampilkan FAB hanya di halaman pengaduan
|
|
||||||
if (controller.activeTabIndex.value == 2) {
|
|
||||||
return FloatingActionButton(
|
|
||||||
onPressed: () {
|
|
||||||
// TODO: Implementasi navigasi ke halaman buat pengaduan
|
|
||||||
Get.toNamed('/buat-pengaduan');
|
|
||||||
},
|
|
||||||
backgroundColor: AppTheme.primaryColor,
|
|
||||||
child: const Icon(Icons.add),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,19 @@ class BantuanCard extends StatelessWidget {
|
|||||||
vertical: 4,
|
vertical: 4,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (item.statusPenyaluran != null &&
|
||||||
|
item.statusPenyaluran!.isNotEmpty)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 4),
|
||||||
|
child: _buildPenyaluranStatusBadge(
|
||||||
|
item.statusPenyaluran!,
|
||||||
|
fontSize: 10,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
vertical: 4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
formattedJumlah,
|
formattedJumlah,
|
||||||
@ -159,11 +172,17 @@ class BantuanCard extends StatelessWidget {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
StatusBadge(status: item.statusPenyaluran ?? ""),
|
||||||
StatusBadge(
|
StatusBadge(
|
||||||
status: item.statusPenerimaan ?? 'MENUNGGU',
|
status: item.statusPenerimaan ?? 'MENUNGGU',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
if (item.deskripsiPenyaluran != null &&
|
if (item.deskripsiPenyaluran != null &&
|
||||||
item.deskripsiPenyaluran!.isNotEmpty)
|
item.deskripsiPenyaluran!.isNotEmpty)
|
||||||
Padding(
|
Padding(
|
||||||
@ -276,4 +295,51 @@ class BantuanCard extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Widget untuk menampilkan badge status penyaluran
|
||||||
|
Widget _buildPenyaluranStatusBadge(
|
||||||
|
String status, {
|
||||||
|
double fontSize = 12,
|
||||||
|
EdgeInsets padding =
|
||||||
|
const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||||
|
}) {
|
||||||
|
Color statusColor;
|
||||||
|
String statusText;
|
||||||
|
|
||||||
|
switch (status.toUpperCase()) {
|
||||||
|
case 'DIJADWALKAN':
|
||||||
|
case 'DISETUJUI':
|
||||||
|
statusColor = Colors.blue;
|
||||||
|
statusText = 'Dijadwalkan';
|
||||||
|
break;
|
||||||
|
case 'TERLAKSANA':
|
||||||
|
statusColor = Colors.green;
|
||||||
|
statusText = 'Terlaksana';
|
||||||
|
break;
|
||||||
|
case 'BATALTERLAKSANA':
|
||||||
|
statusColor = Colors.red;
|
||||||
|
statusText = 'Dibatalkan';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
statusColor = Colors.grey;
|
||||||
|
statusText = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
padding: padding,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: statusColor.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
border: Border.all(color: statusColor),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
statusText,
|
||||||
|
style: TextStyle(
|
||||||
|
color: statusColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: fontSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,10 @@ class StatusBadge extends StatelessWidget {
|
|||||||
'TINDAKAN': Colors.orange,
|
'TINDAKAN': Colors.orange,
|
||||||
'SELESAI': Colors.green,
|
'SELESAI': Colors.green,
|
||||||
'TERVERIFIKASI': Colors.green,
|
'TERVERIFIKASI': Colors.green,
|
||||||
|
'BELUMMENERIMA': Colors.orange,
|
||||||
|
'DIJADWALKAN': Colors.blue,
|
||||||
|
'TERLAKSANA': Colors.purple,
|
||||||
|
'AKTIF': Colors.green,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default labels for common statuses
|
// Default labels for common statuses
|
||||||
@ -42,6 +46,10 @@ class StatusBadge extends StatelessWidget {
|
|||||||
'TINDAKAN': 'Tindakan',
|
'TINDAKAN': 'Tindakan',
|
||||||
'SELESAI': 'Selesai',
|
'SELESAI': 'Selesai',
|
||||||
'TERVERIFIKASI': 'Terverifikasi',
|
'TERVERIFIKASI': 'Terverifikasi',
|
||||||
|
'BELUMMENERIMA': 'Belum Menerima',
|
||||||
|
'DIJADWALKAN': 'Dijadwalkan',
|
||||||
|
'TERLAKSANA': 'Terlaksana',
|
||||||
|
'AKTIF': 'Aktif',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine color and label based on status
|
// Determine color and label based on status
|
||||||
|
Reference in New Issue
Block a user