Hapus tampilan dashboard Petugas Desa dan perbarui routing

- Hapus file petugas_desa_dashboard_view.dart
- Perbarui app_pages.dart untuk menggunakan PetugasDesaView dan PetugasDesaBinding
- Pindahkan logika dashboard ke modul petugas_desa yang baru
- Sesuaikan routing untuk dashboard Petugas Desa
This commit is contained in:
Khafidh Fuadi
2025-03-08 16:39:48 +07:00
parent 539fad3cda
commit 10ed95b3ac
12 changed files with 1850 additions and 635 deletions

View File

@ -0,0 +1,56 @@
import 'package:flutter/material.dart';
class GreetingHeader extends StatelessWidget {
final String name;
final String role;
final String? desa;
const GreetingHeader({
super.key,
required this.name,
required this.role,
this.desa,
});
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withAlpha(26), // 0.1 * 255 ≈ 26
spreadRadius: 1,
blurRadius: 3,
offset: const Offset(0, 1),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Selamat Datang, $name!',
style: textTheme.headlineSmall?.copyWith(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 5),
Text(
'Kamu Login Sebagai $role${desa != null ? ' $desa' : ''}.',
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
);
}
}

View File

@ -0,0 +1,133 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:penyaluran_app/app/theme/app_theme.dart';
class ProgressSection extends StatelessWidget {
final double progressValue;
final int total;
final int distributed;
final int scheduled;
final int unscheduled;
const ProgressSection({
super.key,
required this.progressValue,
required this.total,
required this.distributed,
required this.scheduled,
required this.unscheduled,
});
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
gradient: AppTheme.primaryGradient,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Progress Penyaluran',
style: textTheme.titleMedium?.copyWith(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 10),
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: LinearProgressIndicator(
value: progressValue,
minHeight: 10,
backgroundColor: Colors.white.withOpacity(0.3),
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
),
),
const SizedBox(height: 10),
Text(
'${(progressValue * 100).toInt()}% Selesai',
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 10),
_buildProgressDetailRow('Telah Menerima', distributed, textTheme),
_buildProgressDetailRow('Dijedwalkan', scheduled, textTheme),
_buildProgressDetailRow('Belum Dijadwalkan', unscheduled, textTheme),
const SizedBox(height: 5),
Text(
'Total : $total Penerima, Telah Disalurkan : $distributed Penerima, Belum Disalurkan : ${total - distributed}',
style: textTheme.bodySmall?.copyWith(
fontSize: 12,
color: Colors.white.withOpacity(0.8),
),
),
],
),
);
}
Widget _buildProgressDetailRow(String label, int value, TextTheme textTheme) {
final percentage = total > 0 ? (value / total) : 0.0;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
children: [
Expanded(
flex: 5,
child: Text(
label,
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
color: Colors.white,
),
),
),
Expanded(
flex: 5,
child: Stack(
children: [
Container(
height: 8,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.3),
borderRadius: BorderRadius.circular(4),
),
),
Container(
height: 8,
width: (MediaQuery.of(Get.context!).size.width - 32) *
0.5 *
percentage,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
),
],
),
),
const SizedBox(width: 10),
Text(
'$value',
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
);
}
}

View File

@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
import 'package:penyaluran_app/app/theme/app_theme.dart';
class ScheduleCard extends StatelessWidget {
final String title;
final String location;
final String dateTime;
final bool isToday;
final VoidCallback? onTap;
const ScheduleCard({
super.key,
required this.title,
required this.location,
required this.dateTime,
this.isToday = true,
this.onTap,
});
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return GestureDetector(
onTap: onTap,
child: 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(
title,
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
color: Colors.white.withAlpha(204), // 0.8 * 255 ≈ 204
),
),
const SizedBox(height: 8),
Text(
location,
style: textTheme.titleLarge?.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 8),
Text(
dateTime,
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
color: Colors.white,
),
),
],
),
),
);
}
}