Perbarui beberapa file konfigurasi fingerprint untuk arsitektur arm64-v8a, armeabi-v7a, x86, dan x86_64. Modifikasi tampilan dan controller di modul donatur dan petugas desa untuk meningkatkan pengalaman pengguna, termasuk penggantian logika pengambilan data dan penyesuaian tampilan. Hapus kode yang tidak digunakan dan tambahkan fungsionalitas baru untuk mendukung pengelolaan data yang lebih baik.
This commit is contained in:
@ -44,6 +44,12 @@ class WargaDashboardController extends GetxController {
|
||||
// Jumlah notifikasi belum dibaca
|
||||
final RxInt jumlahNotifikasiBelumDibaca = 0.obs;
|
||||
|
||||
// Variabel untuk mengontrol auto-refresh
|
||||
final RxBool _autoRefreshEnabled = true.obs;
|
||||
|
||||
// Getter untuk status auto-refresh
|
||||
bool get isAutoRefreshEnabled => _autoRefreshEnabled.value;
|
||||
|
||||
// Getter untuk data user
|
||||
BaseUserModel? get user => _authController.baseUser;
|
||||
String get role => user?.role ?? 'WARGA';
|
||||
@ -74,6 +80,14 @@ class WargaDashboardController extends GetxController {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Getter untuk NIK
|
||||
String? get nik {
|
||||
if (_authController.isWarga && _authController.roleData != null) {
|
||||
return (_authController.roleData as WargaModel).nik;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Getter untuk foto profil
|
||||
String? get profilePhotoUrl {
|
||||
// 1. Coba ambil dari fotoProfil yang sudah disimpan
|
||||
@ -121,35 +135,18 @@ class WargaDashboardController extends GetxController {
|
||||
void loadUserData() {
|
||||
currentUser.value = _authController.baseUser;
|
||||
|
||||
// Tambahkan log debugging
|
||||
print('DEBUG WARGA: Memuat data user dari AuthController');
|
||||
print('DEBUG WARGA: baseUser: ${_authController.baseUser}');
|
||||
print('DEBUG WARGA: roleData: ${_authController.roleData}');
|
||||
print('DEBUG WARGA: nama yang akan ditampilkan: $nama');
|
||||
print(
|
||||
'DEBUG WARGA: displayName dari auth controller: ${_authController.displayName}');
|
||||
|
||||
// Kurangi log debugging
|
||||
if (_authController.userData != null) {
|
||||
print(
|
||||
'DEBUG WARGA: userData ada, role: ${_authController.userData!.baseUser.roleName}');
|
||||
|
||||
if (_authController.isWarga) {
|
||||
print('DEBUG WARGA: User adalah warga');
|
||||
var wargaData = _authController.roleData;
|
||||
print('DEBUG WARGA: Data warga: ${wargaData?.namaLengkap}');
|
||||
|
||||
// Ambil foto profil dari wargaData jika ada
|
||||
if (wargaData != null &&
|
||||
wargaData.fotoProfil != null &&
|
||||
wargaData.fotoProfil!.isNotEmpty) {
|
||||
fotoProfil.value = wargaData.fotoProfil!;
|
||||
print('DEBUG WARGA: Foto profil dari roleData: ${fotoProfil.value}');
|
||||
}
|
||||
} else {
|
||||
print('DEBUG WARGA: User bukan warga');
|
||||
}
|
||||
} else {
|
||||
print('DEBUG WARGA: userData null');
|
||||
}
|
||||
|
||||
// Ambil foto profil dari database
|
||||
@ -169,9 +166,6 @@ class WargaDashboardController extends GetxController {
|
||||
|
||||
if (wargaData != null && wargaData['foto_profil'] != null) {
|
||||
fotoProfil.value = wargaData['foto_profil'];
|
||||
print('DEBUG WARGA: Foto profil dari API: ${fotoProfil.value}');
|
||||
} else {
|
||||
print('DEBUG WARGA: Foto profil tidak ditemukan atau null');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error fetching profile photo: $e');
|
||||
@ -211,18 +205,13 @@ class WargaDashboardController extends GetxController {
|
||||
// Reset data terlebih dahulu untuk memastikan tidak ada data lama yang tersimpan
|
||||
penerimaPenyaluran.clear();
|
||||
|
||||
// Log untuk debugging
|
||||
print('DEBUG PENERIMAAN: Memulai fetchPenerimaPenyaluran()');
|
||||
|
||||
// Pastikan user sudah login dan memiliki ID
|
||||
if (user?.id == null) {
|
||||
print('DEBUG PENERIMAAN: User ID null, tidak bisa mengambil data');
|
||||
return [];
|
||||
}
|
||||
|
||||
// Gunakan langsung ID pengguna sebagai warga_id
|
||||
final wargaId = user!.id;
|
||||
print('DEBUG PENERIMAAN: Mengambil data untuk warga ID: $wargaId');
|
||||
|
||||
// Ambil data penerima penyaluran dengan join ke warga, stok bantuan, dan penyaluran bantuan
|
||||
final response =
|
||||
@ -240,9 +229,6 @@ class WargaDashboardController extends GetxController {
|
||||
)
|
||||
''').eq('warga_id', wargaId).order('created_at', ascending: false);
|
||||
|
||||
print(
|
||||
'DEBUG PENERIMAAN: Respons diterima dengan ${response.length} item');
|
||||
|
||||
final List<PenerimaPenyaluranModel> penerima = [];
|
||||
|
||||
// Loop melalui setiap data penerima
|
||||
@ -329,7 +315,6 @@ class WargaDashboardController extends GetxController {
|
||||
|
||||
var model = PenerimaPenyaluranModel.fromJson(sanitizedPenerimaData);
|
||||
penerima.add(model);
|
||||
print('DEBUG PENERIMAAN: Berhasil parse item: ${model.id}');
|
||||
} catch (parseError) {
|
||||
print('DEBUG PENERIMAAN: Error parsing item: $parseError');
|
||||
print('DEBUG PENERIMAAN: Data yang gagal di-parse: $item');
|
||||
@ -340,19 +325,10 @@ class WargaDashboardController extends GetxController {
|
||||
if (penerima.isNotEmpty) {
|
||||
// Update nilai observable
|
||||
penerimaPenyaluran.assignAll(penerima);
|
||||
print(
|
||||
'DEBUG PENERIMAAN: Berhasil assign ${penerima.length} item ke list');
|
||||
|
||||
var diterima =
|
||||
penerima.where((p) => p.statusPenerimaan == 'DITERIMA').length;
|
||||
totalPenyaluranDiterima.value = diterima;
|
||||
|
||||
// Log untuk debugging
|
||||
print(
|
||||
'Berhasil memuat ${penerima.length} data penerimaan untuk warga ID: $wargaId');
|
||||
} else {
|
||||
print(
|
||||
'DEBUG PENERIMAAN: Tidak ada data penerimaan yang berhasil di-parse');
|
||||
}
|
||||
|
||||
return penerima;
|
||||
@ -628,12 +604,23 @@ class WargaDashboardController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
// Metode untuk mengatur apakah auto-refresh diaktifkan atau tidak
|
||||
void setAutoRefreshEnabled(bool enabled) {
|
||||
_autoRefreshEnabled.value = enabled;
|
||||
}
|
||||
|
||||
// Metode untuk refresh data setelah update profil atau kembali ke halaman
|
||||
Future<void> refreshData() async {
|
||||
print('DEBUG WARGA: Memulai refresh data...');
|
||||
Future<void> refreshData({bool silent = false}) async {
|
||||
// Cek apakah auto-refresh diaktifkan
|
||||
if (!_autoRefreshEnabled.value) {
|
||||
if (!silent) print('Auto-refresh dinonaktifkan, melewati refresh data');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!silent) print('Memulai refresh data...');
|
||||
await _authController.refreshUserData(); // Refresh data dari server
|
||||
loadUserData(); // Muat ulang data ke variabel lokal
|
||||
fetchData(); // Ambil data terkait lainnya
|
||||
print('DEBUG WARGA: Refresh data selesai');
|
||||
if (!silent) print('Refresh data selesai');
|
||||
}
|
||||
}
|
||||
|
306
lib/app/modules/warga/views/form_pengaduan_view.dart
Normal file
306
lib/app/modules/warga/views/form_pengaduan_view.dart
Normal file
@ -0,0 +1,306 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart';
|
||||
|
||||
class FormPengaduanView extends StatefulWidget {
|
||||
final String uidPenerimaan;
|
||||
final String? judul;
|
||||
final String? deskripsi;
|
||||
final List<File>? selectedImages;
|
||||
|
||||
const FormPengaduanView({
|
||||
Key? key,
|
||||
required this.uidPenerimaan,
|
||||
this.judul,
|
||||
this.deskripsi,
|
||||
this.selectedImages,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<FormPengaduanView> createState() => _FormPengaduanViewState();
|
||||
}
|
||||
|
||||
class _FormPengaduanViewState extends State<FormPengaduanView> {
|
||||
final WargaDashboardController wargaController =
|
||||
Get.find<WargaDashboardController>();
|
||||
|
||||
static final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||
|
||||
final TextEditingController _titleController = TextEditingController();
|
||||
final TextEditingController _descriptionController = TextEditingController();
|
||||
|
||||
bool _isSubmitting = false;
|
||||
List<File> _selectedImages = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
wargaController.setAutoRefreshEnabled(false);
|
||||
|
||||
// Isi form dengan data yang diberikan jika ada
|
||||
if (widget.judul != null) {
|
||||
_titleController.text = widget.judul!;
|
||||
}
|
||||
if (widget.deskripsi != null) {
|
||||
_descriptionController.text = widget.deskripsi!;
|
||||
}
|
||||
if (widget.selectedImages != null && widget.selectedImages!.isNotEmpty) {
|
||||
_selectedImages = List.from(widget.selectedImages!);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_titleController.dispose();
|
||||
_descriptionController.dispose();
|
||||
wargaController.setAutoRefreshEnabled(true);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _pickImage(ImageSource source) async {
|
||||
try {
|
||||
final ImagePicker picker = ImagePicker();
|
||||
final XFile? image = await picker.pickImage(
|
||||
source: source,
|
||||
imageQuality: 80,
|
||||
);
|
||||
|
||||
if (image != null) {
|
||||
setState(() {
|
||||
_selectedImages.add(File(image.path));
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
Get.snackbar(
|
||||
'Error',
|
||||
'Tidak dapat memilih gambar: $e',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _removeImage(int index) {
|
||||
setState(() {
|
||||
_selectedImages.removeAt(index);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _submitComplaint() async {
|
||||
if (_formKey.currentState!.validate() && !_isSubmitting) {
|
||||
try {
|
||||
setState(() {
|
||||
_isSubmitting = true;
|
||||
});
|
||||
|
||||
// Menutup keyboard sebelum memproses
|
||||
FocusScope.of(context).unfocus();
|
||||
|
||||
// Menyiapkan data foto
|
||||
List<String> fotoPaths =
|
||||
_selectedImages.map((file) => file.path).toList();
|
||||
|
||||
final success = await wargaController.addPengaduan(
|
||||
judul: _titleController.text,
|
||||
deskripsi: _descriptionController.text,
|
||||
penerimaPenyaluranId: widget.uidPenerimaan,
|
||||
fotoPengaduanPaths: fotoPaths,
|
||||
);
|
||||
|
||||
if (success) {
|
||||
Get.back(result: true);
|
||||
}
|
||||
} catch (e) {
|
||||
Get.snackbar(
|
||||
'Error',
|
||||
'Gagal mengirim pengaduan: $e',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
);
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isSubmitting = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Form Pengaduan'),
|
||||
backgroundColor: Get.theme.primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Input Judul Pengaduan
|
||||
TextFormField(
|
||||
controller: _titleController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Judul Pengaduan',
|
||||
border: OutlineInputBorder(),
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 12, vertical: 16),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Judul pengaduan tidak boleh kosong';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Input Deskripsi Pengaduan
|
||||
TextFormField(
|
||||
controller: _descriptionController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Deskripsi Pengaduan',
|
||||
border: OutlineInputBorder(),
|
||||
alignLabelWithHint: true,
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 12, vertical: 16),
|
||||
),
|
||||
maxLines: 5,
|
||||
textInputAction: TextInputAction.done,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Deskripsi pengaduan tidak boleh kosong';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
// Button untuk memilih gambar
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _pickImage(ImageSource.gallery),
|
||||
icon: const Icon(Icons.photo_library),
|
||||
label: const Text('Galeri'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _pickImage(ImageSource.camera),
|
||||
icon: const Icon(Icons.camera_alt),
|
||||
label: const Text('Kamera'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Tampilkan gambar-gambar jika sudah dipilih
|
||||
if (_selectedImages.isNotEmpty) ...[
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Foto Pengaduan:',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
height: 120,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: _selectedImages.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Stack(
|
||||
children: [
|
||||
Container(
|
||||
width: 120,
|
||||
height: 120,
|
||||
margin: const EdgeInsets.only(right: 8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
image: DecorationImage(
|
||||
image: FileImage(_selectedImages[index]),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
right: 13,
|
||||
child: GestureDetector(
|
||||
onTap: () => _removeImage(index),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.white,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 24),
|
||||
// Button untuk submit pengaduan
|
||||
SizedBox(
|
||||
height: 48,
|
||||
child: ElevatedButton(
|
||||
onPressed: _isSubmitting ? null : _submitComplaint,
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: Colors.orange.shade700,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
child: _isSubmitting
|
||||
? const SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation<Color>(Colors.white),
|
||||
),
|
||||
)
|
||||
: const Text(
|
||||
'Kirim Pengaduan',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -5,10 +5,11 @@ import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_con
|
||||
import 'package:penyaluran_app/app/routes/app_pages.dart';
|
||||
import 'package:penyaluran_app/app/widgets/bantuan_card.dart';
|
||||
import 'package:penyaluran_app/app/widgets/section_header.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penerima_penyaluran_model.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/views/form_pengaduan_view.dart';
|
||||
|
||||
class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
const WargaDashboardView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -16,7 +17,6 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
if (controller.isLoading.value) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
controller.fetchData();
|
||||
@ -150,10 +150,10 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
child: Column(
|
||||
children: [
|
||||
_buildInfoRow(
|
||||
icon: Icons.home_rounded,
|
||||
iconColor: Colors.blue.shade300,
|
||||
label: 'Alamat',
|
||||
value: controller.alamat ?? 'Alamat tidak tersedia',
|
||||
icon: Icons.numbers_rounded,
|
||||
iconColor: Colors.green.shade300,
|
||||
label: 'NIK',
|
||||
value: controller.nik ?? 'NIK tidak tersedia',
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
@ -175,31 +175,19 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
label: 'Desa',
|
||||
value: controller.desa ?? 'Desa tidak tersedia',
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
child: Divider(height: 1),
|
||||
),
|
||||
_buildInfoRow(
|
||||
icon: Icons.home_rounded,
|
||||
iconColor: Colors.blue.shade300,
|
||||
label: 'Alamat Lengkap',
|
||||
value: controller.alamat ?? 'Alamat tidak tersedia',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildActionButton(
|
||||
icon: Icons.edit_rounded,
|
||||
label: 'Edit Profil',
|
||||
color: Colors.blue.shade700,
|
||||
onTap: () => Get.toNamed(Routes.PROFILE),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: _buildActionButton(
|
||||
icon: Icons.notifications_rounded,
|
||||
label: 'Notifikasi',
|
||||
color: Colors.amber.shade700,
|
||||
onTap: () => Get.toNamed(Routes.NOTIFIKASI),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -299,7 +287,6 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
}
|
||||
|
||||
Widget _buildStatisticSection() {
|
||||
// Data untuk statistik
|
||||
final totalBantuan = controller.penerimaPenyaluran.length;
|
||||
final totalDiterima = controller.penerimaPenyaluran
|
||||
.where((item) => item.statusPenerimaan == 'DITERIMA')
|
||||
@ -341,7 +328,6 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
),
|
||||
],
|
||||
),
|
||||
// Progress bar untuk persentase bantuan yang diterima
|
||||
if (totalBantuan > 0) ...[
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
@ -443,7 +429,6 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
decimalDigits: 0,
|
||||
);
|
||||
|
||||
// Hitung total bantuan uang dan non-uang
|
||||
double totalUang = 0;
|
||||
Map<String, double> totalNonUang = {};
|
||||
|
||||
@ -742,4 +727,146 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showBuatPengaduanDialog(BuildContext context) {
|
||||
// Daftar penerimaan bantuan yang dapat diadukan (status DITERIMA)
|
||||
final bantuanDiterima = controller.penerimaPenyaluran
|
||||
.where((item) => item.statusPenerimaan == 'DITERIMA')
|
||||
.toList();
|
||||
|
||||
// Jika tidak ada bantuan yang diterima
|
||||
if (bantuanDiterima.isEmpty) {
|
||||
Get.snackbar(
|
||||
'Informasi',
|
||||
'Tidak ada bantuan yang sudah diterima untuk dapat diajukan pengaduan',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.orange,
|
||||
colorText: Colors.white,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Variabel untuk menyimpan pilihan penerimaan
|
||||
PenerimaPenyaluranModel? selectedPenerimaan = bantuanDiterima.first;
|
||||
|
||||
Get.dialog(
|
||||
Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.report_problem,
|
||||
color: Colors.orange.shade700,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
const Text(
|
||||
'Buat Pengaduan Baru',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const Text(
|
||||
'Pilih Bantuan yang Ingin Diadukan:',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<PenerimaPenyaluranModel>(
|
||||
isExpanded: true,
|
||||
value: selectedPenerimaan,
|
||||
items: bantuanDiterima.map((item) {
|
||||
String displayText = item.namaPenyaluran ?? 'Bantuan';
|
||||
if (item.tanggalPenerimaan != null) {
|
||||
displayText +=
|
||||
' (${DateFormat('dd/MM/yyyy').format(item.tanggalPenerimaan!)})';
|
||||
}
|
||||
|
||||
return DropdownMenuItem<PenerimaPenyaluranModel>(
|
||||
value: item,
|
||||
child: Text(displayText),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
setState(() {
|
||||
selectedPenerimaan = value;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
if (selectedPenerimaan != null) {
|
||||
Get.back();
|
||||
Get.to(
|
||||
() => FormPengaduanView(
|
||||
uidPenerimaan: selectedPenerimaan!.id.toString(),
|
||||
),
|
||||
transition: Transition.rightToLeft,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
);
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.orange.shade700,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'Lanjutkan',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1301,13 +1301,13 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
|
||||
Get.back(); // Tutup dialog terlebih dahulu
|
||||
|
||||
// Tampilkan loading
|
||||
Get.dialog(
|
||||
const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
barrierDismissible: false,
|
||||
);
|
||||
// // Tampilkan loading
|
||||
// Get.dialog(
|
||||
// const Center(
|
||||
// child: CircularProgressIndicator(),
|
||||
// ),
|
||||
// barrierDismissible: false,
|
||||
// );
|
||||
|
||||
bool success = false;
|
||||
try {
|
||||
@ -1336,18 +1336,6 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
// Refresh data halaman
|
||||
await controller.fetchPengaduan();
|
||||
await controller.fetchPenerimaPenyaluran();
|
||||
|
||||
Get.snackbar(
|
||||
'Sukses',
|
||||
'Pengaduan berhasil dikirim dan data diperbarui',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.green,
|
||||
colorText: Colors.white,
|
||||
duration: const Duration(seconds: 3),
|
||||
);
|
||||
|
||||
// Navigate ke halaman pengaduan jika berhasil
|
||||
controller.changeTab(2); // Tab pengaduan
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
|
@ -1,40 +1,48 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penerima_penyaluran_model.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/views/form_pengaduan_view.dart';
|
||||
import 'package:penyaluran_app/app/utils/date_time_helper.dart';
|
||||
import 'dart:io';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
class WargaPengaduanView extends GetView<WargaDashboardController> {
|
||||
const WargaPengaduanView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(() {
|
||||
if (controller.isLoading.value) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
return Scaffold(
|
||||
body: Obx(() {
|
||||
if (controller.isLoading.value) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
// Debug print untuk melihat jumlah item
|
||||
print('DEBUG: Jumlah pengaduan tersedia: ${controller.pengaduan.length}');
|
||||
// Debug print untuk melihat jumlah item
|
||||
print(
|
||||
'DEBUG: Jumlah pengaduan tersedia: ${controller.pengaduan.length}');
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
// Tambahkan delay untuk memastikan refresh indicator terlihat
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
controller.fetchData();
|
||||
},
|
||||
child: controller.pengaduan.isEmpty
|
||||
? ListView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: [
|
||||
SizedBox(
|
||||
height: Get.height * 0.7,
|
||||
child: _buildEmptyState(),
|
||||
),
|
||||
],
|
||||
)
|
||||
: _buildPengaduanList(context),
|
||||
);
|
||||
});
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
// Tambahkan delay untuk memastikan refresh indicator terlihat
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
controller.fetchData();
|
||||
},
|
||||
child: controller.pengaduan.isEmpty
|
||||
? ListView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: [
|
||||
SizedBox(
|
||||
height: Get.height * 0.7,
|
||||
child: _buildEmptyState(),
|
||||
),
|
||||
],
|
||||
)
|
||||
: _buildPengaduanList(context),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEmptyState() {
|
||||
@ -89,8 +97,6 @@ class WargaPengaduanView extends GetView<WargaDashboardController> {
|
||||
}
|
||||
|
||||
final item = controller.pengaduan[index];
|
||||
print(
|
||||
'DEBUG: Membangun item pengaduan $index dengan id: ${item.id}');
|
||||
|
||||
// Tentukan status dan warna berdasarkan status pengaduan
|
||||
Color statusColor;
|
||||
|
@ -16,16 +16,16 @@ class WargaView extends GetView<WargaDashboardController> {
|
||||
Widget build(BuildContext context) {
|
||||
// Tambahkan listener untuk refresh data saat fokus didapatkan kembali
|
||||
// misalnya ketika kembali dari halaman profil
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final focusNode = FocusNode();
|
||||
FocusScope.of(context).requestFocus(focusNode);
|
||||
focusNode.addListener(() {
|
||||
if (focusNode.hasFocus) {
|
||||
print('DEBUG WARGA: Halaman mendapatkan fokus, memuat ulang data');
|
||||
controller.refreshData();
|
||||
}
|
||||
});
|
||||
});
|
||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
// final focusNode = FocusNode();
|
||||
// FocusScope.of(context).requestFocus(focusNode);
|
||||
// focusNode.addListener(() {
|
||||
// if (focusNode.hasFocus) {
|
||||
// print('DEBUG WARGA: Halaman mendapatkan fokus, memuat ulang data');
|
||||
// controller.refreshData();
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
|
Reference in New Issue
Block a user