import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:penyaluran_app/app/data/models/pengaduan_model.dart'; import 'package:penyaluran_app/app/data/models/tindakan_pengaduan_model.dart'; import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart'; import 'package:penyaluran_app/app/theme/app_theme.dart'; import 'package:timeline_tile/timeline_tile.dart'; class WargaDetailPengaduanView extends GetView { const WargaDetailPengaduanView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final Map args = Get.arguments ?? {}; final String pengaduanId = args['id'] ?? ''; if (pengaduanId.isEmpty) { return Scaffold( appBar: AppBar( title: const Text('Detail Pengaduan'), ), body: const Center( child: Text('ID Pengaduan tidak valid'), ), ); } return Scaffold( appBar: AppBar( title: const Text('Detail Pengaduan'), elevation: 0, ), body: FutureBuilder>( future: controller.getDetailPengaduan(pengaduanId), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return Center( child: Text('Error: ${snapshot.error}'), ); } final data = snapshot.data; if (data == null || data['pengaduan'] == null) { return const Center( child: Text('Data pengaduan tidak ditemukan'), ); } final pengaduan = PengaduanModel.fromJson(data['pengaduan']); final List tindakanList = (data['tindakan'] as List) .map((item) => TindakanPengaduanModel.fromJson(item)) .toList(); return _buildDetailContent(context, pengaduan, tindakanList); }, ), ); } Widget _buildDetailContent( BuildContext context, PengaduanModel pengaduan, List tindakanList, ) { // Tentukan status dan warna Color statusColor; String statusText; switch (pengaduan.status?.toUpperCase()) { case 'MENUNGGU': statusColor = Colors.orange; statusText = 'Menunggu'; break; case 'TINDAKAN': statusColor = Colors.blue; statusText = 'Tindakan'; break; case 'SELESAI': statusColor = Colors.green; statusText = 'Selesai'; break; default: statusColor = Colors.grey; statusText = pengaduan.status ?? 'Tidak Diketahui'; } return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header dengan status _buildHeaderWithStatus(context, pengaduan, statusColor, statusText), const SizedBox(height: 24), // Informasi penyaluran yang diadukan if (pengaduan.penerimaPenyaluran != null) _buildPenyaluranInfo(context, pengaduan), const SizedBox(height: 24), // Timeline tindakan _buildTindakanTimeline(context, tindakanList), ], ), ); } Widget _buildHeaderWithStatus( BuildContext context, PengaduanModel pengaduan, Color statusColor, String statusText, ) { return Card( elevation: 2, shape: RoundedRectangleBorder( 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( pengaduan.judul ?? 'Pengaduan', style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), ), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), 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: 12, ), ), ), ], ), const SizedBox(height: 12), Text( pengaduan.deskripsi ?? '', style: TextStyle( fontSize: 14, color: Colors.grey.shade700, ), ), const SizedBox(height: 12), Row( children: [ Icon( Icons.calendar_today, size: 16, color: Colors.grey.shade600, ), const SizedBox(width: 8), Text( pengaduan.tanggalPengaduan != null ? DateFormat('dd MMMM yyyy', 'id_ID') .format(pengaduan.tanggalPengaduan!) : '-', style: TextStyle( color: Colors.grey.shade600, ), ), ], ), ], ), ), ); } Widget _buildPenyaluranInfo(BuildContext context, PengaduanModel pengaduan) { return Card( elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Informasi Penyaluran', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), _buildInfoRow('Nama Penyaluran', pengaduan.namaPenyaluran), _buildInfoRow('Jenis Bantuan', pengaduan.jenisBantuan), _buildInfoRow('Jumlah Bantuan', pengaduan.jumlahBantuan), _buildInfoRow('Deskripsi', pengaduan.deskripsiPenyaluran), ], ), ), ); } Widget _buildTindakanTimeline( BuildContext context, List tindakanList, ) { if (tindakanList.isEmpty) { return Card( elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: const Padding( padding: EdgeInsets.all(16), child: Center( child: Text( 'Pengaduan Anda sedang menunggu tindakan dari petugas', style: TextStyle( fontSize: 14, fontStyle: FontStyle.italic, color: Colors.grey, ), ), ), ), ); } return Card( elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Riwayat Tindakan', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: tindakanList.length, itemBuilder: (context, index) { final tindakan = tindakanList[index]; final bool isFirst = index == 0; final bool isLast = index == tindakanList.length - 1; return _buildTimelineTile( context, tindakan, isFirst, isLast, ); }, ), ], ), ), ); } Widget _buildTimelineTile( BuildContext context, TindakanPengaduanModel tindakan, bool isFirst, bool isLast, ) { Color dotColor; switch (tindakan.statusTindakan) { case 'SELESAI': dotColor = Colors.green; break; case 'PROSES': dotColor = Colors.blue; break; default: dotColor = Colors.grey; } return TimelineTile( alignment: TimelineAlign.start, isFirst: isFirst, isLast: isLast, indicatorStyle: IndicatorStyle( width: 20, color: dotColor, iconStyle: IconStyle( color: Colors.white, iconData: tindakan.statusTindakan == 'SELESAI' ? Icons.check : Icons.sync, ), ), endChild: Container( margin: const EdgeInsets.only(left: 16, bottom: 24), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), spreadRadius: 1, blurRadius: 2, offset: const Offset(0, 1), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( tindakan.kategoriTindakanText, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: dotColor.withOpacity(0.1), borderRadius: BorderRadius.circular(4), ), child: Text( tindakan.statusTindakanText, style: TextStyle( color: dotColor, fontSize: 12, fontWeight: FontWeight.bold, ), ), ), ], ), const SizedBox(height: 8), Text( tindakan.tindakan ?? '', style: const TextStyle(fontSize: 14), ), if (tindakan.hasilTindakan != null && tindakan.hasilTindakan!.isNotEmpty) ...[ const SizedBox(height: 8), Text( 'Hasil: ${tindakan.hasilTindakan}', style: TextStyle( fontSize: 12, color: Colors.grey.shade700, ), ), ], const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Oleh: ${tindakan.namaPetugas}', style: TextStyle( fontSize: 12, color: Colors.grey.shade600, ), ), Text( tindakan.tanggalTindakan != null ? DateFormat('dd MMM yyyy', 'id_ID') .format(tindakan.tanggalTindakan!) : '-', style: TextStyle( fontSize: 12, color: Colors.grey.shade600, ), ), ], ), ], ), ), ); } Widget _buildInfoRow(String label, String value) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 120, child: Text( '$label:', style: TextStyle( fontWeight: FontWeight.w500, color: Colors.grey.shade700, ), ), ), Expanded( child: Text( value, style: const TextStyle( color: Colors.black87, ), ), ), ], ), ); } }