Perbarui judul aplikasi dari 'Penyaluran App' menjadi 'Penerimaan App'. Tambahkan properti baru pada model PenerimaPenyaluranModel untuk mendukung informasi tambahan terkait penyaluran. Modifikasi tampilan di WargaDashboardView dan WargaPengaduanView untuk meningkatkan pengalaman pengguna. Hapus WargaPenyaluranView yang tidak digunakan dan perbarui rute aplikasi untuk mencerminkan perubahan ini.
This commit is contained in:
280
lib/app/widgets/bantuan_card.dart
Normal file
280
lib/app/widgets/bantuan_card.dart
Normal file
@ -0,0 +1,280 @@
|
||||
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/widgets/status_badge.dart';
|
||||
|
||||
class BantuanCard extends StatelessWidget {
|
||||
final PenerimaPenyaluranModel item;
|
||||
final VoidCallback? onTap;
|
||||
final bool isCompact;
|
||||
|
||||
const BantuanCard({
|
||||
Key? key,
|
||||
required this.item,
|
||||
this.onTap,
|
||||
this.isCompact = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final currencyFormat = NumberFormat.currency(
|
||||
locale: 'id',
|
||||
symbol: 'Rp ',
|
||||
decimalDigits: 0,
|
||||
);
|
||||
|
||||
// Format jumlah bantuan berdasarkan tipe (uang atau bukan)
|
||||
String formattedJumlah = '';
|
||||
if (item.jumlahBantuan != null) {
|
||||
if (item.isUang == true) {
|
||||
formattedJumlah = currencyFormat.format(item.jumlahBantuan);
|
||||
} else {
|
||||
formattedJumlah = '${item.jumlahBantuan} ${item.satuan ?? ''}';
|
||||
}
|
||||
} else {
|
||||
formattedJumlah = '-';
|
||||
}
|
||||
|
||||
// Tampilan kompak untuk daftar ringkasan
|
||||
if (isCompact) {
|
||||
return Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: (item.isUang == true ? Colors.green : Colors.blue)
|
||||
.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Icon(
|
||||
item.isUang == true
|
||||
? Icons.attach_money
|
||||
: Icons.inventory_2,
|
||||
color: item.isUang == true ? Colors.green : Colors.blue,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
item.namaPenyaluran ?? item.keterangan ?? 'Bantuan',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
item.kategoriNama ?? 'Bantuan',
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade700,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
item.tanggalPenerimaan != null
|
||||
? DateFormat('dd MMMM yyyy', 'id_ID')
|
||||
.format(item.tanggalPenerimaan!)
|
||||
: '-',
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
StatusBadge(
|
||||
status: item.statusPenerimaan ?? 'MENUNGGU',
|
||||
fontSize: 10,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
formattedJumlah,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: item.isUang == true ? Colors.green : Colors.blue,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Tampilan detail untuk halaman daftar lengkap
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 2,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.namaPenyaluran ?? item.keterangan ?? 'Bantuan',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
StatusBadge(
|
||||
status: item.statusPenerimaan ?? 'MENUNGGU',
|
||||
),
|
||||
],
|
||||
),
|
||||
if (item.deskripsiPenyaluran != null &&
|
||||
item.deskripsiPenyaluran!.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
item.deskripsiPenyaluran!,
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade700,
|
||||
fontSize: 14,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.category,
|
||||
size: 16,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
item.kategoriNama ?? 'Bantuan',
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade700,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
item.tanggalPenerimaan != null
|
||||
? DateFormat('dd MMMM yyyy', 'id_ID')
|
||||
.format(item.tanggalPenerimaan!)
|
||||
: '-',
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.location_on,
|
||||
size: 16,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.lokasiPenyaluranNama ?? 'Lokasi tidak tersedia',
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
item.isUang == true
|
||||
? Icons.attach_money
|
||||
: Icons.inventory_2,
|
||||
size: 16,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
formattedJumlah,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: item.isUang == true ? Colors.green : Colors.blue,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(height: 1),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton.icon(
|
||||
onPressed: onTap,
|
||||
icon: const Icon(Icons.visibility),
|
||||
label: const Text('Lihat Detail'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
51
lib/app/widgets/section_header.dart
Normal file
51
lib/app/widgets/section_header.dart
Normal file
@ -0,0 +1,51 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SectionHeader extends StatelessWidget {
|
||||
final String title;
|
||||
final VoidCallback? onViewAll;
|
||||
final String? viewAllText;
|
||||
final Widget? trailing;
|
||||
final EdgeInsets padding;
|
||||
final TextStyle? titleStyle;
|
||||
|
||||
const SectionHeader({
|
||||
Key? key,
|
||||
required this.title,
|
||||
this.onViewAll,
|
||||
this.viewAllText = 'Lihat Semua',
|
||||
this.trailing,
|
||||
this.padding = const EdgeInsets.only(bottom: 12),
|
||||
this.titleStyle,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: padding,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: titleStyle ??
|
||||
const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
if (trailing != null)
|
||||
trailing!
|
||||
else if (onViewAll != null)
|
||||
TextButton(
|
||||
onPressed: onViewAll,
|
||||
child: Text(viewAllText!),
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
minimumSize: const Size(0, 36),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
79
lib/app/widgets/status_badge.dart
Normal file
79
lib/app/widgets/status_badge.dart
Normal file
@ -0,0 +1,79 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StatusBadge extends StatelessWidget {
|
||||
final String status;
|
||||
final Map<String, Color>? customColors;
|
||||
final Map<String, String>? customLabels;
|
||||
final double fontSize;
|
||||
final EdgeInsets padding;
|
||||
|
||||
const StatusBadge({
|
||||
Key? key,
|
||||
required this.status,
|
||||
this.customColors,
|
||||
this.customLabels,
|
||||
this.fontSize = 12,
|
||||
this.padding = const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final String statusUpper = status.toUpperCase();
|
||||
|
||||
// Default colors for common statuses
|
||||
final Map<String, Color> defaultColors = {
|
||||
'DITERIMA': Colors.green,
|
||||
'MENUNGGU': Colors.orange,
|
||||
'DITOLAK': Colors.red,
|
||||
'PROSES': Colors.orange,
|
||||
'DIPROSES': Colors.orange,
|
||||
'TINDAKAN': Colors.orange,
|
||||
'SELESAI': Colors.green,
|
||||
'TERVERIFIKASI': Colors.green,
|
||||
};
|
||||
|
||||
// Default labels for common statuses
|
||||
final Map<String, String> defaultLabels = {
|
||||
'DITERIMA': 'Diterima',
|
||||
'MENUNGGU': 'Menunggu',
|
||||
'DITOLAK': 'Ditolak',
|
||||
'PROSES': 'Proses',
|
||||
'DIPROSES': 'Proses',
|
||||
'TINDAKAN': 'Tindakan',
|
||||
'SELESAI': 'Selesai',
|
||||
'TERVERIFIKASI': 'Terverifikasi',
|
||||
};
|
||||
|
||||
// Determine color and label based on status
|
||||
final Color color =
|
||||
(customColors != null && customColors!.containsKey(statusUpper))
|
||||
? customColors![statusUpper]!
|
||||
: defaultColors.containsKey(statusUpper)
|
||||
? defaultColors[statusUpper]!
|
||||
: Colors.grey;
|
||||
|
||||
final String label =
|
||||
(customLabels != null && customLabels!.containsKey(statusUpper))
|
||||
? customLabels![statusUpper]!
|
||||
: defaultLabels.containsKey(statusUpper)
|
||||
? defaultLabels[statusUpper]!
|
||||
: status;
|
||||
|
||||
return Container(
|
||||
padding: padding,
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(color: color),
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: fontSize,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user