1919 lines
66 KiB
Dart
1919 lines
66 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:penyaluran_app/app/data/models/skema_bantuan_model.dart';
|
|
import 'package:penyaluran_app/app/data/models/stok_bantuan_model.dart';
|
|
import 'package:penyaluran_app/app/modules/donatur/controllers/donatur_dashboard_controller.dart';
|
|
import 'package:penyaluran_app/app/widgets/section_header.dart';
|
|
import 'dart:io';
|
|
|
|
class DonaturPenitipanView extends GetView<DonaturDashboardController> {
|
|
const DonaturPenitipanView({super.key});
|
|
|
|
@override
|
|
DonaturDashboardController get controller {
|
|
if (!Get.isRegistered<DonaturDashboardController>(
|
|
tag: 'donatur_dashboard',
|
|
)) {
|
|
return Get.put(
|
|
DonaturDashboardController(),
|
|
tag: 'donatur_dashboard',
|
|
permanent: true,
|
|
);
|
|
}
|
|
return Get.find<DonaturDashboardController>(tag: 'donatur_dashboard');
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return FormPenitipanBantuan();
|
|
}
|
|
}
|
|
|
|
class FormPenitipanBantuan extends StatefulWidget {
|
|
const FormPenitipanBantuan({super.key});
|
|
|
|
@override
|
|
_FormPenitipanBantuanState createState() => _FormPenitipanBantuanState();
|
|
}
|
|
|
|
class _FormPenitipanBantuanState extends State<FormPenitipanBantuan> {
|
|
final DonaturDashboardController controller =
|
|
Get.find<DonaturDashboardController>(tag: 'donatur_dashboard');
|
|
|
|
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
|
String? selectedStokBantuanId;
|
|
String? selectedSkemaBantuanId;
|
|
String? selectedLokasiPenyaluranId;
|
|
final TextEditingController jumlahController = TextEditingController();
|
|
final TextEditingController deskripsiController = TextEditingController();
|
|
|
|
bool _isProsedurinfoExpanded = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
// Reset foto bantuan saat form dibuka
|
|
controller.resetFotoBantuan();
|
|
|
|
// Cek apakah ada skema bantuan yang dipilih dari halaman skema
|
|
if (controller.selectedSkemaBantuanId.isNotEmpty) {
|
|
// Aktifkan tab skema bantuan
|
|
setState(() {
|
|
selectedSkemaBantuanId = controller.selectedSkemaBantuanId.value;
|
|
});
|
|
|
|
// Reset ID skema setelah digunakan
|
|
Future.delayed(Duration.zero, () {
|
|
controller.selectedSkemaBantuanId.value = '';
|
|
});
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Obx(() {
|
|
if (controller.isLoading.value) {
|
|
return const Center(child: CircularProgressIndicator());
|
|
}
|
|
|
|
return Form(
|
|
key: formKey,
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// Bagian Header dengan prosedur singkat
|
|
_buildHeader(),
|
|
const SizedBox(height: 8),
|
|
|
|
// Prosedur Penitipan Bantuan
|
|
_buildProsedurPenitipan(),
|
|
const SizedBox(height: 24),
|
|
|
|
// Pilih metode penitipan
|
|
_buildMetodePenitipanSection(),
|
|
const SizedBox(height: 24),
|
|
|
|
// Form berdasarkan pilihan
|
|
if (selectedSkemaBantuanId != null) ...[
|
|
_buildFormSkemaBantuan(),
|
|
] else ...[
|
|
_buildFormBantuanManual(),
|
|
],
|
|
|
|
// Jumlah bantuan
|
|
_buildJumlahBantuan(),
|
|
const SizedBox(height: 16),
|
|
|
|
// Lokasi Penitipan
|
|
_buildLokasiPenitipan(),
|
|
const SizedBox(height: 16),
|
|
|
|
// Deskripsi bantuan
|
|
_buildDeskripsiBantuan(),
|
|
const SizedBox(height: 16),
|
|
|
|
// Foto bantuan
|
|
_buildFotoBantuan(),
|
|
const SizedBox(height: 24),
|
|
|
|
// Tombol kirim
|
|
_buildSubmitButton(),
|
|
const SizedBox(height: 24),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
}
|
|
|
|
Widget _buildHeader() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.shade50,
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: Icon(
|
|
Icons.volunteer_activism,
|
|
color: Colors.blue.shade700,
|
|
size: 28,
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
'Formulir Penitipan Bantuan',
|
|
style: TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'Isi formulir untuk mencatat bantuan yang telah Anda titipkan',
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
color: Colors.grey.shade600,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildProsedurPenitipan() {
|
|
return Card(
|
|
elevation: 1,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
side: BorderSide(color: Colors.blue.shade100),
|
|
),
|
|
color: Colors.blue.shade50,
|
|
child: Column(
|
|
children: [
|
|
// Header dengan tombol toggle
|
|
InkWell(
|
|
onTap: () {
|
|
setState(() {
|
|
_isProsedurinfoExpanded = !_isProsedurinfoExpanded;
|
|
});
|
|
},
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.shade100,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(
|
|
Icons.info_outline,
|
|
color: Colors.blue.shade800,
|
|
size: 20,
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
const Expanded(
|
|
child: Text(
|
|
'Prosedur Penitipan Bantuan',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
Icon(
|
|
_isProsedurinfoExpanded
|
|
? Icons.keyboard_arrow_up
|
|
: Icons.keyboard_arrow_down,
|
|
color: Colors.blue.shade800,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
// Konten prosedur yang bisa di-expand
|
|
AnimatedCrossFade(
|
|
duration: const Duration(milliseconds: 300),
|
|
crossFadeState: _isProsedurinfoExpanded
|
|
? CrossFadeState.showSecond
|
|
: CrossFadeState.showFirst,
|
|
firstChild: const SizedBox(height: 0),
|
|
secondChild: Padding(
|
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
|
child: Column(
|
|
children: [
|
|
const Divider(),
|
|
const SizedBox(height: 8),
|
|
|
|
// Langkah-langkah prosedur
|
|
_buildProsedurStep(
|
|
number: '1',
|
|
title: 'Penitipan Bantuan',
|
|
description:
|
|
'Titipkan bantuan Anda langsung ke lokasi penyaluran yang tersedia',
|
|
icon: Icons.local_shipping,
|
|
),
|
|
|
|
_buildProsedurStep(
|
|
number: '2',
|
|
title: 'Ambil Bukti Foto',
|
|
description:
|
|
'Ambil foto sebagai bukti bantuan yang telah dititipkan',
|
|
icon: Icons.camera_alt,
|
|
),
|
|
|
|
_buildProsedurStep(
|
|
number: '3',
|
|
title: 'Isi Formulir',
|
|
description:
|
|
'Lengkapi formulir ini untuk mencatat penitipan bantuan Anda',
|
|
icon: Icons.edit_document,
|
|
),
|
|
|
|
_buildProsedurStep(
|
|
number: '4',
|
|
title: 'Verifikasi Petugas',
|
|
description:
|
|
'Petugas desa akan memverifikasi penitipan bantuan Anda',
|
|
icon: Icons.verified_user,
|
|
isLast: true,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildProsedurStep({
|
|
required String number,
|
|
required String title,
|
|
required String description,
|
|
required IconData icon,
|
|
bool isLast = false,
|
|
}) {
|
|
return Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// Nomor dalam lingkaran
|
|
Container(
|
|
width: 28,
|
|
height: 28,
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.shade700,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
number,
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(icon, size: 18, color: Colors.blue.shade700),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
title,
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.blue.shade900,
|
|
fontSize: 15,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
description,
|
|
style: const TextStyle(fontSize: 14),
|
|
),
|
|
if (!isLast) ...[
|
|
SizedBox(
|
|
height: 30,
|
|
child: Padding(
|
|
padding: const EdgeInsets.only(left: 13),
|
|
child: VerticalDivider(
|
|
color: Colors.blue.shade300,
|
|
thickness: 1,
|
|
width: 1,
|
|
),
|
|
),
|
|
),
|
|
] else
|
|
const SizedBox(height: 8),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
// Bagian lainnya akan dikembangkan dalam edit selanjutnya
|
|
|
|
Widget _buildMetodePenitipanSection() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(Icons.category_outlined, color: Colors.grey.shade700),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Metode Penitipan',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
|
|
// Tab pilihan metode yang lebih menarik
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade200,
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: InkWell(
|
|
onTap: () {
|
|
setState(() {
|
|
// Reset semua data saat berpindah ke bantuan manual
|
|
selectedSkemaBantuanId = null;
|
|
selectedStokBantuanId = null;
|
|
jumlahController.clear();
|
|
});
|
|
},
|
|
child: Container(
|
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
|
decoration: BoxDecoration(
|
|
color: selectedSkemaBantuanId == null
|
|
? Colors.blue.shade600
|
|
: Colors.transparent,
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
alignment: Alignment.center,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
Icons.inventory_2_outlined,
|
|
size: 18,
|
|
color: selectedSkemaBantuanId == null
|
|
? Colors.white
|
|
: Colors.grey.shade800,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Bantuan Manual',
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
color: selectedSkemaBantuanId == null
|
|
? Colors.white
|
|
: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Expanded(
|
|
child: InkWell(
|
|
onTap: () {
|
|
setState(() {
|
|
// Reset semua data saat berpindah ke skema bantuan
|
|
selectedStokBantuanId = null;
|
|
selectedSkemaBantuanId = '';
|
|
jumlahController.clear();
|
|
});
|
|
},
|
|
child: Container(
|
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
|
decoration: BoxDecoration(
|
|
color: selectedSkemaBantuanId != null
|
|
? Colors.blue.shade600
|
|
: Colors.transparent,
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
alignment: Alignment.center,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
Icons.schema_outlined,
|
|
size: 18,
|
|
color: selectedSkemaBantuanId != null
|
|
? Colors.white
|
|
: Colors.grey.shade800,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Dari Skema Bantuan',
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
color: selectedSkemaBantuanId != null
|
|
? Colors.white
|
|
: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildFormSkemaBantuan() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(Icons.schema, color: Colors.grey.shade700),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Pilih Skema Bantuan',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
border: Border.all(color: Colors.grey.shade300),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: DropdownButtonFormField<String>(
|
|
decoration: InputDecoration(
|
|
border: InputBorder.none,
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 16,
|
|
vertical: 12,
|
|
),
|
|
hintText: 'Pilih skema bantuan',
|
|
prefixIcon: Icon(Icons.category, color: Colors.blue.shade600),
|
|
),
|
|
value: selectedSkemaBantuanId == '' ? null : selectedSkemaBantuanId,
|
|
items: controller.skemaBantuan.map((skema) {
|
|
return DropdownMenuItem<String>(
|
|
value: skema.id,
|
|
child: Text(skema.nama ?? 'Tidak ada nama'),
|
|
);
|
|
}).toList(),
|
|
onChanged: (value) {
|
|
setState(() {
|
|
selectedSkemaBantuanId = value;
|
|
// Jika skema dipilih, isi otomatis stok bantuan sesuai dengan skema
|
|
if (value != null) {
|
|
final selectedSkema = controller.skemaBantuan.firstWhere(
|
|
(skema) => skema.id == value,
|
|
orElse: () => SkemaBantuanModel(),
|
|
);
|
|
selectedStokBantuanId = selectedSkema.stokBantuanId;
|
|
|
|
// Isi otomatis jumlah jika ada
|
|
if (selectedSkema.jumlahDiterimaPerOrang != null) {
|
|
jumlahController.text =
|
|
selectedSkema.jumlahDiterimaPerOrang.toString();
|
|
}
|
|
}
|
|
});
|
|
},
|
|
validator: (value) {
|
|
if (selectedSkemaBantuanId != null &&
|
|
(value == null || value.isEmpty)) {
|
|
return 'Skema bantuan harus dipilih';
|
|
}
|
|
return null;
|
|
},
|
|
dropdownColor: Colors.white,
|
|
icon: Icon(Icons.arrow_drop_down, color: Colors.blue.shade600),
|
|
isExpanded: true,
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
|
|
// Tampilkan informasi stok bantuan dari skema yang dipilih
|
|
Builder(
|
|
builder: (context) {
|
|
// Hanya tampilkan jika skema dipilih
|
|
if (selectedSkemaBantuanId == null ||
|
|
selectedSkemaBantuanId!.isEmpty) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
// Cari skema bantuan yang dipilih
|
|
SkemaBantuanModel? selectedSkema;
|
|
try {
|
|
selectedSkema = controller.skemaBantuan.firstWhere(
|
|
(skema) => skema.id == selectedSkemaBantuanId,
|
|
);
|
|
} catch (_) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
// Pastikan skema dan stok bantuan ada
|
|
if (selectedSkema == null || selectedSkema.stokBantuanId == null) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
// Menggunakan Obx hanya untuk data yang reaktif
|
|
return Obx(() {
|
|
// Cari stok bantuan yang sesuai
|
|
StokBantuanModel? selectedStok;
|
|
try {
|
|
if (selectedSkema?.stokBantuanId != null) {
|
|
for (var stok in controller.stokBantuan) {
|
|
if (stok.id == selectedSkema!.stokBantuanId) {
|
|
selectedStok = stok;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} catch (_) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
if (selectedStok == null) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
final stokNama = selectedStok.nama ?? 'Tidak diketahui';
|
|
final stokTotal = selectedStok.totalStok ?? 0.0;
|
|
final stokSatuan = selectedStok.satuan ?? 'item';
|
|
final stokDeskripsi = selectedStok.deskripsi ?? '';
|
|
final isUang = selectedStok.isUang ?? false;
|
|
String kategoriNama = '';
|
|
if (selectedStok.kategoriBantuan != null) {
|
|
kategoriNama = selectedStok.kategoriBantuan!['nama'] ?? '';
|
|
}
|
|
|
|
// Format stok total jika berbentuk uang
|
|
String formattedStokTotal;
|
|
if (isUang) {
|
|
formattedStokTotal = 'Rp ${_formatCurrency(stokTotal)}';
|
|
} else {
|
|
formattedStokTotal = '$stokTotal $stokSatuan';
|
|
}
|
|
|
|
// Tampilkan informasi stok bantuan dengan desain yang lebih menarik
|
|
return Container(
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: isUang ? Colors.green.shade50 : Colors.blue.shade50,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(
|
|
color: isUang
|
|
? Colors.green.shade200
|
|
: Colors.blue.shade200),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(
|
|
isUang ? Icons.monetization_on : Icons.inventory_2,
|
|
color: isUang
|
|
? Colors.green.shade700
|
|
: Colors.blue.shade700,
|
|
size: 20,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Informasi Stok Bantuan',
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
color: isUang
|
|
? Colors.green.shade700
|
|
: Colors.blue.shade700,
|
|
fontSize: 15,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: _buildInfoItem(
|
|
icon:
|
|
isUang ? Icons.payment_rounded : Icons.category,
|
|
label: 'Jenis Bantuan',
|
|
value: stokNama,
|
|
iconColor: isUang
|
|
? Colors.green.shade600
|
|
: Colors.blue.shade600,
|
|
),
|
|
),
|
|
Expanded(
|
|
child: _buildInfoItem(
|
|
icon: isUang
|
|
? Icons.account_balance_wallet
|
|
: Icons.inventory,
|
|
label: 'Stok Tersedia',
|
|
value: formattedStokTotal,
|
|
iconColor: isUang
|
|
? Colors.green.shade600
|
|
: Colors.blue.shade600,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
if (kategoriNama.isNotEmpty) ...[
|
|
const SizedBox(height: 8),
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: _buildInfoItem(
|
|
icon: Icons.category_outlined,
|
|
label: 'Kategori',
|
|
value: kategoriNama,
|
|
iconColor: isUang
|
|
? Colors.green.shade600
|
|
: Colors.blue.shade600,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
if (stokDeskripsi.isNotEmpty) ...[
|
|
const SizedBox(height: 8),
|
|
const Divider(color: Colors.white70),
|
|
const SizedBox(height: 8),
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Icon(Icons.description,
|
|
size: 16,
|
|
color: isUang
|
|
? Colors.green.shade700
|
|
: Colors.blue.shade700),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'Deskripsi',
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.grey.shade700,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
stokDeskripsi,
|
|
style: TextStyle(
|
|
fontSize: 13,
|
|
color: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
],
|
|
),
|
|
);
|
|
});
|
|
},
|
|
),
|
|
|
|
const SizedBox(height: 16),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildInfoItem(
|
|
{required IconData icon,
|
|
required String label,
|
|
required String value,
|
|
Color? iconColor}) {
|
|
return Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(icon, size: 18, color: iconColor ?? Colors.blue.shade600),
|
|
),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
label,
|
|
style: const TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
value,
|
|
style: const TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 14,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildFormBantuanManual() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(Icons.inventory_2, color: Colors.grey.shade700),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Jenis Bantuan',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
border: Border.all(color: Colors.grey.shade300),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: DropdownButtonFormField<String>(
|
|
decoration: InputDecoration(
|
|
border: InputBorder.none,
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 16,
|
|
vertical: 12,
|
|
),
|
|
hintText: 'Pilih jenis bantuan',
|
|
prefixIcon: Icon(Icons.category, color: Colors.blue.shade600),
|
|
),
|
|
value: selectedStokBantuanId,
|
|
items: controller.getAvailableStokBantuan().map((stok) {
|
|
String displayText;
|
|
if (stok.isUang ?? false) {
|
|
displayText =
|
|
'${stok.nama ?? 'Tidak ada nama'} (Saldo: Rp ${_formatCurrency(stok.totalStok ?? 0)})';
|
|
} else {
|
|
displayText =
|
|
'${stok.nama ?? 'Tidak ada nama'} (Stok: ${stok.totalStok ?? 0} ${stok.satuan ?? 'item'})';
|
|
}
|
|
return DropdownMenuItem<String>(
|
|
value: stok.id,
|
|
child: Text(displayText),
|
|
);
|
|
}).toList(),
|
|
onChanged: (value) {
|
|
setState(() {
|
|
selectedStokBantuanId = value;
|
|
});
|
|
},
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Jenis bantuan harus dipilih';
|
|
}
|
|
return null;
|
|
},
|
|
dropdownColor: Colors.white,
|
|
icon: Icon(Icons.arrow_drop_down, color: Colors.blue.shade600),
|
|
isExpanded: true,
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// Menampilkan informasi stok bantuan yang dipilih
|
|
Builder(
|
|
builder: (context) {
|
|
if (selectedStokBantuanId == null) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
return Obx(() {
|
|
// Cari stok bantuan yang sesuai
|
|
StokBantuanModel? selectedStok;
|
|
try {
|
|
selectedStok = controller.stokBantuan.firstWhere(
|
|
(stok) => stok.id == selectedStokBantuanId,
|
|
orElse: () => StokBantuanModel(),
|
|
);
|
|
} catch (_) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
if (selectedStok.id == null) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
final stokNama = selectedStok.nama ?? 'Tidak diketahui';
|
|
final stokTotal = selectedStok.totalStok ?? 0.0;
|
|
final stokSatuan = selectedStok.satuan ?? 'item';
|
|
final stokDeskripsi = selectedStok.deskripsi ?? '';
|
|
final isUang = selectedStok.isUang ?? false;
|
|
String kategoriNama = '';
|
|
if (selectedStok.kategoriBantuan != null) {
|
|
kategoriNama = selectedStok.kategoriBantuan!['nama'] ?? '';
|
|
}
|
|
|
|
// Format stok total jika berbentuk uang
|
|
String formattedStokTotal;
|
|
if (isUang) {
|
|
formattedStokTotal = 'Rp ${_formatCurrency(stokTotal)}';
|
|
} else {
|
|
formattedStokTotal = '$stokTotal $stokSatuan';
|
|
}
|
|
|
|
// Tampilkan informasi stok bantuan dengan desain yang lebih menarik
|
|
return Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: isUang ? Colors.green.shade50 : Colors.blue.shade50,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(
|
|
color:
|
|
isUang ? Colors.green.shade200 : Colors.blue.shade200,
|
|
),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(
|
|
isUang ? Icons.monetization_on : Icons.inventory_2,
|
|
color: isUang
|
|
? Colors.green.shade700
|
|
: Colors.blue.shade700,
|
|
size: 20,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Informasi Stok Bantuan',
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
color: isUang
|
|
? Colors.green.shade700
|
|
: Colors.blue.shade700,
|
|
fontSize: 15,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: _buildInfoItem(
|
|
icon:
|
|
isUang ? Icons.payment_rounded : Icons.category,
|
|
label: 'Jenis Bantuan',
|
|
value: stokNama,
|
|
iconColor: isUang
|
|
? Colors.green.shade600
|
|
: Colors.blue.shade600,
|
|
),
|
|
),
|
|
Expanded(
|
|
child: _buildInfoItem(
|
|
icon: isUang
|
|
? Icons.account_balance_wallet
|
|
: Icons.inventory,
|
|
label: 'Stok Tersedia',
|
|
value: formattedStokTotal,
|
|
iconColor: isUang
|
|
? Colors.green.shade600
|
|
: Colors.blue.shade600,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
if (kategoriNama.isNotEmpty) ...[
|
|
const SizedBox(height: 8),
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: _buildInfoItem(
|
|
icon: Icons.category_outlined,
|
|
label: 'Kategori',
|
|
value: kategoriNama,
|
|
iconColor: isUang
|
|
? Colors.green.shade600
|
|
: Colors.blue.shade600,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
if (stokDeskripsi.isNotEmpty) ...[
|
|
const SizedBox(height: 8),
|
|
const Divider(color: Colors.white70),
|
|
const SizedBox(height: 8),
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Icon(Icons.description,
|
|
size: 16,
|
|
color: isUang
|
|
? Colors.green.shade700
|
|
: Colors.blue.shade700),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'Deskripsi',
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.grey.shade700,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
stokDeskripsi,
|
|
style: TextStyle(
|
|
fontSize: 13,
|
|
color: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
],
|
|
),
|
|
);
|
|
});
|
|
},
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildJumlahBantuan() {
|
|
final isUang = _isSelectedStokUang();
|
|
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(
|
|
// Tampilkan ikon uang jika stok bantuan berbentuk uang
|
|
isUang ? Icons.payment_rounded : Icons.numbers,
|
|
color: Colors.grey.shade700),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Jumlah Bantuan',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
border: Border.all(color: Colors.grey.shade300),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: TextFormField(
|
|
controller: jumlahController,
|
|
keyboardType: TextInputType.number,
|
|
decoration: InputDecoration(
|
|
border: InputBorder.none,
|
|
hintText:
|
|
isUang ? 'Masukkan jumlah uang' : 'Masukkan jumlah bantuan',
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 16,
|
|
vertical: 12,
|
|
),
|
|
prefixIcon: Icon(
|
|
isUang ? Icons.monetization_on : Icons.shopping_bag,
|
|
color: Colors.blue.shade600),
|
|
// Tambahkan prefix teks "Rp" jika berbentuk uang
|
|
prefixText: isUang ? 'Rp ' : null,
|
|
),
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Jumlah harus diisi';
|
|
}
|
|
|
|
String numericOnly = value;
|
|
if (isUang) {
|
|
numericOnly = value.replaceAll('.', '');
|
|
}
|
|
|
|
if (double.tryParse(numericOnly) == null) {
|
|
return 'Jumlah harus berupa angka';
|
|
}
|
|
if (double.parse(numericOnly) <= 0) {
|
|
return 'Jumlah harus lebih dari 0';
|
|
}
|
|
return null;
|
|
},
|
|
onChanged: (value) {
|
|
if (isUang && value.isNotEmpty) {
|
|
// Format input sebagai currency jika stok berbentuk uang
|
|
final numericValue =
|
|
value.replaceAll('.', '').replaceAll('Rp ', '');
|
|
if (double.tryParse(numericValue) != null) {
|
|
final formattedValue =
|
|
_formatCurrency(double.parse(numericValue));
|
|
|
|
// Hindari infinite loop dengan mengecek apakah nilai sudah berubah
|
|
if (formattedValue != value) {
|
|
jumlahController.value = TextEditingValue(
|
|
text: formattedValue,
|
|
selection: TextSelection.collapsed(
|
|
offset: formattedValue.length),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
),
|
|
),
|
|
if (isUang) ...[
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
'Masukkan jumlah dalam Rupiah tanpa desimal',
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.grey.shade600,
|
|
fontStyle: FontStyle.italic,
|
|
),
|
|
),
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
// Helper function untuk mengecek apakah stok bantuan yang dipilih berbentuk uang
|
|
bool _isSelectedStokUang() {
|
|
if (selectedStokBantuanId == null) return false;
|
|
|
|
try {
|
|
for (var stok in controller.stokBantuan) {
|
|
if (stok.id == selectedStokBantuanId) {
|
|
return stok.isUang ?? false;
|
|
}
|
|
}
|
|
return false;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Helper function untuk memformat angka sebagai currency
|
|
String _formatCurrency(double value) {
|
|
// Format ke currency dengan pemisah ribuan
|
|
final formatted = value.toInt().toString().replaceAllMapped(
|
|
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
|
|
(Match match) => '${match[1]}.',
|
|
);
|
|
return formatted;
|
|
}
|
|
|
|
Widget _buildLokasiPenitipan() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(Icons.location_on, color: Colors.grey.shade700),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Lokasi Penitipan',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
border: Border.all(color: Colors.grey.shade300),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: DropdownButtonFormField<String>(
|
|
decoration: InputDecoration(
|
|
border: InputBorder.none,
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 16,
|
|
vertical: 12,
|
|
),
|
|
hintText: 'Pilih lokasi penitipan',
|
|
prefixIcon: Icon(Icons.place, color: Colors.blue.shade600),
|
|
),
|
|
value: selectedLokasiPenyaluranId,
|
|
items: controller.lokasiPenyaluran.map((lokasi) {
|
|
String alamatLengkap = [
|
|
lokasi.alamatLengkap,
|
|
lokasi.desa,
|
|
lokasi.kecamatan,
|
|
lokasi.kabupaten,
|
|
].where((s) => s != null && s.isNotEmpty).join(', ');
|
|
|
|
return DropdownMenuItem<String>(
|
|
value: lokasi.id,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
lokasi.nama,
|
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
),
|
|
if (alamatLengkap.isNotEmpty)
|
|
Text(
|
|
alamatLengkap,
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.grey.shade600,
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
onChanged: (value) {
|
|
setState(() {
|
|
selectedLokasiPenyaluranId = value;
|
|
});
|
|
},
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Lokasi penitipan harus dipilih';
|
|
}
|
|
return null;
|
|
},
|
|
dropdownColor: Colors.white,
|
|
icon: Icon(Icons.arrow_drop_down, color: Colors.blue.shade600),
|
|
isExpanded: true,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildDeskripsiBantuan() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(Icons.description, color: Colors.grey.shade700),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Deskripsi Bantuan',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
border: Border.all(color: Colors.grey.shade300),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: TextFormField(
|
|
controller: deskripsiController,
|
|
maxLines: 3,
|
|
decoration: InputDecoration(
|
|
border: InputBorder.none,
|
|
hintText: 'Deskripsi bantuan yang dititipkan',
|
|
contentPadding: const EdgeInsets.all(16),
|
|
),
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Deskripsi harus diisi';
|
|
}
|
|
return null;
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildFotoBantuan() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(Icons.photo_camera, color: Colors.grey.shade700),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Foto Bantuan',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.grey.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
'Upload minimal 1 foto sebagai bukti bantuan yang dititipkan',
|
|
style: TextStyle(
|
|
fontSize: 13,
|
|
color: Colors.grey.shade600,
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
|
|
// Widget untuk foto bantuan dengan desain lebih menarik
|
|
Obx(() {
|
|
return controller.fotoBantuanPaths.isNotEmpty
|
|
? Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// Tampilkan foto yang sudah dipilih
|
|
SizedBox(
|
|
height: 140,
|
|
child: ListView.builder(
|
|
scrollDirection: Axis.horizontal,
|
|
itemCount: controller.fotoBantuanPaths.length +
|
|
1, // +1 untuk tombol tambah
|
|
itemBuilder: (context, index) {
|
|
if (index == controller.fotoBantuanPaths.length) {
|
|
// Tombol tambah foto
|
|
return GestureDetector(
|
|
onTap: _showPilihSumberFoto,
|
|
child: Container(
|
|
width: 120,
|
|
margin: const EdgeInsets.only(right: 12),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade100,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(
|
|
color: Colors.blue.shade200,
|
|
width: 1.5,
|
|
),
|
|
),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(10),
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.shade50,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(
|
|
Icons.add_a_photo,
|
|
size: 28,
|
|
color: Colors.blue.shade600,
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
'Tambah Foto',
|
|
style: TextStyle(
|
|
color: Colors.blue.shade600,
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 14,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// Tampilkan foto yang sudah dipilih
|
|
return Container(
|
|
width: 120,
|
|
height: 140,
|
|
margin: const EdgeInsets.only(right: 12),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(
|
|
color: Colors.grey.shade300,
|
|
),
|
|
),
|
|
child: Stack(
|
|
children: [
|
|
// Foto
|
|
ClipRRect(
|
|
borderRadius: BorderRadius.circular(12),
|
|
child: Image.file(
|
|
File(controller.fotoBantuanPaths[index]),
|
|
width: 120,
|
|
height: 140,
|
|
fit: BoxFit.cover,
|
|
),
|
|
),
|
|
// Tombol hapus
|
|
Positioned(
|
|
top: 8,
|
|
right: 8,
|
|
child: GestureDetector(
|
|
onTap: () {
|
|
controller.removeFotoBantuan(index);
|
|
},
|
|
child: Container(
|
|
padding: const EdgeInsets.all(4),
|
|
decoration: const BoxDecoration(
|
|
color: Colors.white,
|
|
shape: BoxShape.circle,
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black26,
|
|
blurRadius: 4,
|
|
),
|
|
],
|
|
),
|
|
child: const Icon(
|
|
Icons.close,
|
|
size: 18,
|
|
color: Colors.red,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
)
|
|
: GestureDetector(
|
|
onTap: _showPilihSumberFoto,
|
|
child: Container(
|
|
height: 140,
|
|
width: double.infinity,
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade100,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(
|
|
color: Colors.blue.shade200,
|
|
width: 1.5,
|
|
style: BorderStyle.solid,
|
|
),
|
|
),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.shade50,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(
|
|
Icons.add_a_photo,
|
|
size: 36,
|
|
color: Colors.blue.shade600,
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
Text(
|
|
'Tambah Foto Bantuan',
|
|
style: TextStyle(
|
|
color: Colors.blue.shade700,
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 16,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'Klik untuk mengambil foto bukti bantuan',
|
|
style: TextStyle(
|
|
color: Colors.grey.shade600,
|
|
fontSize: 13,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildSubmitButton() {
|
|
return ElevatedButton.icon(
|
|
onPressed: () {
|
|
if (formKey.currentState!.validate()) {
|
|
// Validasi foto bantuan
|
|
if (controller.fotoBantuanPaths.isEmpty) {
|
|
Get.snackbar(
|
|
'Peringatan',
|
|
'Harap upload setidaknya 1 foto bantuan',
|
|
backgroundColor: Colors.amber,
|
|
colorText: Colors.white,
|
|
duration: const Duration(seconds: 3),
|
|
margin: const EdgeInsets.all(8),
|
|
borderRadius: 8,
|
|
icon:
|
|
const Icon(Icons.warning_amber_rounded, color: Colors.white),
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Tampilkan konfirmasi sebelum mengirim
|
|
_showKonfirmasiPenitipan();
|
|
}
|
|
},
|
|
icon: const Icon(Icons.send),
|
|
label: const Text('Kirim Penitipan Bantuan'),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.green.shade600,
|
|
foregroundColor: Colors.white,
|
|
minimumSize: const Size(double.infinity, 52),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
elevation: 2,
|
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
|
),
|
|
);
|
|
}
|
|
|
|
// Fungsi untuk menampilkan dialog konfirmasi
|
|
void _showKonfirmasiPenitipan() {
|
|
// Dapatkan informasi terkait penitipan untuk ditampilkan di dialog
|
|
String jenisBantuan = '';
|
|
String lokasiPenitipan = '';
|
|
String jumlahBantuan = jumlahController.text;
|
|
bool isUangBantuan = false;
|
|
String tipeBantuan = 'Donasi Langsung';
|
|
String skemaBantuanNama = '';
|
|
|
|
// Ambil nama stok bantuan terpilih
|
|
if (selectedStokBantuanId != null) {
|
|
try {
|
|
var stok = controller.stokBantuan
|
|
.firstWhere((s) => s.id == selectedStokBantuanId);
|
|
jenisBantuan = stok.nama ?? 'Tidak diketahui';
|
|
isUangBantuan = stok.isUang ?? false;
|
|
|
|
// Format jumlah untuk bantuan uang
|
|
if (isUangBantuan && jumlahBantuan.isNotEmpty) {
|
|
// Pastikan sudah format dengan benar
|
|
if (!jumlahBantuan.startsWith('Rp ')) {
|
|
jumlahBantuan =
|
|
'Rp ${_formatCurrency(double.parse(jumlahBantuan.replaceAll('.', '')))}';
|
|
}
|
|
}
|
|
} catch (_) {
|
|
jenisBantuan = 'Tidak diketahui';
|
|
}
|
|
}
|
|
|
|
// Ambil nama skema bantuan jika dipilih
|
|
if (selectedSkemaBantuanId != null && selectedSkemaBantuanId!.isNotEmpty) {
|
|
try {
|
|
var skema = controller.skemaBantuan
|
|
.firstWhere((s) => s.id == selectedSkemaBantuanId);
|
|
skemaBantuanNama = skema.nama ?? 'Tidak diketahui';
|
|
tipeBantuan = 'Bantuan dari Skema: $skemaBantuanNama';
|
|
} catch (_) {
|
|
tipeBantuan = 'Bantuan dari Skema';
|
|
}
|
|
}
|
|
|
|
// Ambil nama lokasi penitipan terpilih
|
|
if (selectedLokasiPenyaluranId != null) {
|
|
try {
|
|
var lokasi = controller.lokasiPenyaluran
|
|
.firstWhere((l) => l.id == selectedLokasiPenyaluranId);
|
|
lokasiPenitipan = lokasi.nama;
|
|
} catch (_) {
|
|
lokasiPenitipan = 'Tidak diketahui';
|
|
}
|
|
}
|
|
|
|
Get.dialog(
|
|
Dialog(
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
|
child: Container(
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: Colors.green.shade50,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(
|
|
Icons.check_circle_outline,
|
|
color: Colors.green.shade700,
|
|
size: 36,
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
const Text(
|
|
'Konfirmasi Penitipan Bantuan',
|
|
style: TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
const SizedBox(height: 8),
|
|
const Text(
|
|
'Pastikan data yang Anda masukkan sudah benar',
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
color: Colors.grey,
|
|
),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
// Detail info penitipan
|
|
Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade50,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(color: Colors.grey.shade200),
|
|
),
|
|
child: Column(
|
|
children: [
|
|
if (selectedSkemaBantuanId != null &&
|
|
selectedSkemaBantuanId!.isNotEmpty) ...[
|
|
_buildDetailRow(
|
|
icon: Icons.schema,
|
|
label: 'Metode Penitipan',
|
|
value: tipeBantuan,
|
|
iconColor: Colors.purple.shade600,
|
|
),
|
|
const Divider(),
|
|
],
|
|
_buildDetailRow(
|
|
icon: isUangBantuan
|
|
? Icons.monetization_on
|
|
: Icons.inventory_2,
|
|
label: 'Jenis Bantuan',
|
|
value: jenisBantuan,
|
|
iconColor: isUangBantuan
|
|
? Colors.green.shade600
|
|
: Colors.blue.shade600,
|
|
),
|
|
const Divider(),
|
|
_buildDetailRow(
|
|
icon: isUangBantuan
|
|
? Icons.payment_rounded
|
|
: Icons.shopping_bag,
|
|
label: 'Jumlah',
|
|
value: jumlahBantuan + (isUangBantuan ? '' : ' item'),
|
|
iconColor: isUangBantuan
|
|
? Colors.green.shade600
|
|
: Colors.blue.shade600,
|
|
),
|
|
const Divider(),
|
|
_buildDetailRow(
|
|
icon: Icons.location_on,
|
|
label: 'Lokasi Penitipan',
|
|
value: lokasiPenitipan,
|
|
iconColor: Colors.orange.shade600,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 24),
|
|
|
|
// Tombol aksi
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: OutlinedButton(
|
|
onPressed: () => Get.back(),
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: Colors.grey.shade700,
|
|
side: BorderSide(color: Colors.grey.shade300),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
|
),
|
|
child: const Text('Batal'),
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: ElevatedButton(
|
|
onPressed: () {
|
|
Get.back();
|
|
// Pastikan jumlah diproses dengan benar
|
|
double jumlahNumerik = isUangBantuan
|
|
? double.parse(jumlahController.text
|
|
.replaceAll('.', '')
|
|
.replaceAll('Rp ', ''))
|
|
: double.parse(jumlahController.text);
|
|
|
|
// Panggil fungsi untuk membuat penitipan bantuan
|
|
controller.createPenitipanBantuan(
|
|
selectedStokBantuanId,
|
|
jumlahNumerik,
|
|
deskripsiController.text,
|
|
selectedSkemaBantuanId,
|
|
selectedLokasiPenyaluranId,
|
|
);
|
|
},
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.green.shade600,
|
|
foregroundColor: Colors.white,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
|
),
|
|
child: const Text('Kirim'),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildDetailRow({
|
|
required IconData icon,
|
|
required String label,
|
|
required String value,
|
|
Color? iconColor,
|
|
}) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade200,
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child:
|
|
Icon(icon, color: iconColor ?? Colors.blue.shade700, size: 18),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
label,
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.grey.shade600,
|
|
),
|
|
),
|
|
Text(
|
|
value,
|
|
style: const TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// Fungsi untuk memilih foto
|
|
void _showPilihSumberFoto() {
|
|
Get.bottomSheet(
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
|
|
decoration: const BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Container(
|
|
height: 5,
|
|
width: 40,
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade300,
|
|
borderRadius: BorderRadius.circular(5),
|
|
),
|
|
margin: const EdgeInsets.only(bottom: 16),
|
|
),
|
|
const Text(
|
|
'Pilih Sumber Foto',
|
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
|
),
|
|
const SizedBox(height: 24),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: [
|
|
_buildSumberFotoOption(
|
|
icon: Icons.camera_alt,
|
|
label: 'Kamera',
|
|
onTap: () {
|
|
Get.back();
|
|
controller.pickImage(isCamera: true);
|
|
},
|
|
),
|
|
_buildSumberFotoOption(
|
|
icon: Icons.photo_library,
|
|
label: 'Galeri',
|
|
onTap: () {
|
|
Get.back();
|
|
controller.pickImage(isCamera: false);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 16),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildSumberFotoOption({
|
|
required IconData icon,
|
|
required String label,
|
|
required VoidCallback onTap,
|
|
}) {
|
|
return InkWell(
|
|
onTap: onTap,
|
|
child: Container(
|
|
width: 100,
|
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.shade50,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(color: Colors.blue.shade200),
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(
|
|
icon,
|
|
color: Colors.blue.shade700,
|
|
size: 36,
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
label,
|
|
style: TextStyle(
|
|
color: Colors.blue.shade700,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildContactInfo({
|
|
required IconData icon,
|
|
required String title,
|
|
required String content,
|
|
}) {
|
|
return Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.blue.shade50,
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(icon, color: Colors.blue, size: 20),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
title,
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
content,
|
|
style: TextStyle(fontSize: 14, color: Colors.grey.shade700),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|