import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; import '/../pages/login_page.dart'; import 'edit_pemeriksaan_balita.dart'; class RiwayatPemeriksaanBalitaPage extends StatefulWidget { final int idBalita; const RiwayatPemeriksaanBalitaPage({ super.key, required this.idBalita, }); @override State createState() => _RiwayatPemeriksaanBalitaPageState(); } class _RiwayatPemeriksaanBalitaPageState extends State { List> _data = []; List> _allData = []; bool _loading = true; bool _checkingLogin = true; int _currentPage = 0; final int _rowsPerPage = 5; @override void initState() { super.initState(); _checkLogin(); } String hitungUsia(String tanggalLahir) { try { DateTime lahir = DateTime.parse(tanggalLahir); DateTime now = DateTime.now(); int tahun = now.year - lahir.year; int bulan = now.month - lahir.month; int hari = now.day - lahir.day; if (hari < 0) { bulan -= 1; hari += DateTime(now.year, now.month, 0).day; } if (bulan < 0) { tahun -= 1; bulan += 12; } return "$tahun thn $bulan bln $hari hr"; } catch (e) { return "-"; } } String _formatTanggalIndo(String? tanggal) { if (tanggal == null || tanggal.isEmpty || tanggal == "-") return "-"; try { DateTime dt = DateTime.parse(tanggal); List bulanIndo = [ "", "Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember" ]; return "${dt.day} ${bulanIndo[dt.month]} ${dt.year}"; } catch (e) { return tanggal; } } Future _checkLogin() async { final prefs = await SharedPreferences.getInstance(); final isLogin = prefs.getBool('isLogin') ?? false; if (!isLogin) { if (!mounted) return; Navigator.pushReplacement( context, MaterialPageRoute(builder: (_) => const LoginPage()), ); return; } setState(() => _checkingLogin = false); _fetchData(); } Future _fetchData() async { setState(() => _loading = true); final url = Uri.parse( 'http://ta.myhost.id/E31230549/mposyandu_api/pemeriksaan_balita/get_riwayat_pemeriksaan_balita.php?id_balita=${widget.idBalita}', ); try { final response = await http.get(url); if (response.statusCode == 200) { final jsonData = json.decode(response.body); if (jsonData["success"] == true) { final List> data = List>.from(jsonData["data"]); setState(() { for (var item in data) { item["jk_formatted"] = item["jenis_kelamin"] == "L" ? "Laki-Laki" : (item["jenis_kelamin"] == "P" ? "Perempuan" : "-"); item["ibu_suami"] = "${item["nama_ibu"] ?? '-'} (${item["nama_suami"] ?? '-'})"; if (item["tanggal_lahir"] != null) { item["usia_formatted"] = hitungUsia(item["tanggal_lahir"]); item["tgl_lahir_formatted"] = _formatTanggalIndo(item["tanggal_lahir"]); } else { item["usia_formatted"] = "-"; item["tgl_lahir_formatted"] = "-"; } item["bb_formatted"] = "${item["bb"] ?? '-'} kg"; item["tb_formatted"] = "${item["tb"] ?? '-'} cm"; item["lk_formatted"] = "${item["lk"] ?? '-'} cm"; } _allData = data; _data = data; _loading = false; }); } else { setState(() { _data = []; _loading = false; }); } } } catch (e) { debugPrint("ERROR FETCH: $e"); setState(() => _loading = false); } } Future _hapusData(int idPemeriksaan) async { final confirm = await showDialog( context: context, builder: (c) => AlertDialog( title: Text("Konfirmasi", style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.bold)), content: Text("Yakin ingin menghapus data ini?", style: GoogleFonts.poppins(fontSize: 12)), actions: [ TextButton( onPressed: () => Navigator.pop(c, false), child: Text("Batal")), OutlinedButton( onPressed: () => Navigator.pop(c, true), style: OutlinedButton.styleFrom( side: const BorderSide(color: Colors.red), shape: const StadiumBorder()), child: Text("Hapus", style: GoogleFonts.poppins( color: Colors.red, fontSize: 12, fontWeight: FontWeight.bold)), ), ], ), ); if (confirm != true) return; try { final url = Uri.parse( "http://ta.myhost.id/E31230549/mposyandu_api/pemeriksaan_balita/hapus_pemeriksaan_balita.php"); final response = await http .post(url, body: {"id_pemeriksaan": idPemeriksaan.toString()}); final res = json.decode(response.body); if (res["success"] == true) { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text("Data berhasil dihapus"))); _fetchData(); } } catch (e) { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text("Gagal hapus: $e"))); } } List> get _paginatedData { if (_data.isEmpty) return []; final start = _currentPage * _rowsPerPage; final end = start + _rowsPerPage; return _data.sublist(start, end > _data.length ? _data.length : end); } @override Widget build(BuildContext context) { if (_checkingLogin) return const Scaffold(body: Center(child: CircularProgressIndicator())); final totalPages = _data.isEmpty ? 1 : (_data.length / _rowsPerPage).ceil(); return Scaffold( backgroundColor: Colors.grey[100], appBar: AppBar( backgroundColor: Colors.blueAccent, elevation: 0, title: const Text(""), leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () => Navigator.pop(context)), ), body: _loading ? const Center(child: CircularProgressIndicator()) : Padding( padding: const EdgeInsets.all(16), child: Column( children: [ Center( child: Text("Data Riwayat Pemeriksaan", style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold))), const SizedBox(height: 15), TextField( style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( hintText: "Cari tanggal pemeriksaan....", prefixIcon: const Icon(Icons.search, size: 20), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10)), filled: true, fillColor: Colors.white, contentPadding: const EdgeInsets.symmetric(vertical: 8), ), onChanged: (value) { setState(() { _data = _allData .where((b) => (b['tanggal_pemeriksaan'] ?? '') .toString() .toLowerCase() .contains(value.toLowerCase())) .toList(); _currentPage = 0; }); }, ), const SizedBox(height: 15), Expanded( child: _data.isEmpty ? Center( child: Text("Tidak ada riwayat pemeriksaan", style: GoogleFonts.poppins(fontSize: 12))) : ListView.builder( itemCount: _paginatedData.length, itemBuilder: (context, index) { final item = _paginatedData[index]; bool isLolos = item["status"] == 'lolos'; String? statusHadir = item["status_hadir"]; return Container( margin: const EdgeInsets.symmetric(vertical: 8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(14), boxShadow: const [ BoxShadow( color: Colors.black12, blurRadius: 8, offset: Offset(0, 4)) ], ), child: Column( children: [ Container( width: double.infinity, padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: isLolos ? Colors.green : Colors.blueAccent, borderRadius: const BorderRadius.vertical( top: Radius.circular(14)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( item["nama_balita"] ?? "-", style: GoogleFonts.poppins( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14), ), ), Row( children: [ // BADGE KEHADIRAN (Hanya muncul jika belum lolos) if (!isLolos && statusHadir != null && statusHadir != "-") Container( margin: const EdgeInsets.only( right: 5), padding: const EdgeInsets .symmetric( horizontal: 8, vertical: 2), decoration: BoxDecoration( color: statusHadir == 'Hadir' ? Colors.green : Colors.red, borderRadius: BorderRadius .circular(10), border: Border.all( color: Colors.white, width: 1), ), child: Text( statusHadir .toUpperCase(), style: GoogleFonts.poppins( fontSize: 10, fontWeight: FontWeight .bold, color: Colors .white), ), ), if (isLolos) Container( padding: const EdgeInsets .symmetric( horizontal: 8, vertical: 2), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius .circular( 10)), child: Text("LOLOS", style: GoogleFonts .poppins( fontSize: 10, fontWeight: FontWeight .bold, color: Colors .green)), ), ], ) ], ), const SizedBox(height: 4), _rowHeader( "Orang Tua", item["ibu_suami"]), _rowHeader("Jenis Kelamin", item["jk_formatted"]), _rowHeader("Tgl Lahir", item["tgl_lahir_formatted"]), _rowHeader("Usia Saat Ini", item["usia_formatted"]), ], ), ), Container( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Hasil Pemeriksaan", style: GoogleFonts.poppins( fontWeight: FontWeight.w600, fontSize: 12, color: Colors.blueAccent)), const Divider(), _rowDetail( "Tanggal Periksa", _formatTanggalIndo( item["tanggal_pemeriksaan"])), _rowDetail("Berat Badan", item["bb_formatted"]), _rowDetail("Tinggi Badan", item["tb_formatted"]), _rowDetail("Lingkar Kepala", item["lk_formatted"]), _rowDetail( "Imunisasi", item["imunisasi"]), _rowDetail( "Vitamin A", item["vitamin_a"]), _rowDetail("PMT", item["pmt"]), _rowDetail( "Catatan", item["catatan"]), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ _actionButton( label: "Edit", icon: Icons.edit, color: Colors.orange, onPressed: () async { final result = await Navigator.push( context, MaterialPageRoute( builder: (_) => EditPemeriksaanBalitaPage( data: item))); if (result == true) _fetchData(); }, ), const SizedBox(width: 8), _actionButton( label: "Hapus", icon: Icons.delete, color: Colors.red, onPressed: () => _hapusData( int.parse( item["id_pemeriksaan"] .toString())), ), ], ), ], ), ), ], ), ); }, ), ), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("Halaman ${_currentPage + 1} dari $totalPages", style: GoogleFonts.poppins(fontSize: 12)), Row( children: [ IconButton( icon: const Icon(Icons.chevron_left, size: 20), onPressed: _currentPage == 0 ? null : () => setState(() => _currentPage--)), IconButton( icon: const Icon(Icons.chevron_right, size: 20), onPressed: _currentPage >= totalPages - 1 ? null : () => setState(() => _currentPage++)), ], ), ], ), ], ), ), ); } Widget _rowHeader(String label, dynamic value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 1), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 95, child: Text(label, style: GoogleFonts.poppins( fontSize: 11, fontWeight: FontWeight.w600, color: Colors.white))), Text(" : ", style: GoogleFonts.poppins( color: Colors.white, fontSize: 11, fontWeight: FontWeight.bold)), Expanded( child: Text("${value ?? '-'}", style: GoogleFonts.poppins( fontSize: 11, color: Colors.white, fontWeight: FontWeight.w400))), ], ), ); } Widget _rowDetail(String label, dynamic value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 105, child: Text(label, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.black87))), Text(" : ", style: GoogleFonts.poppins( fontSize: 12, color: Colors.black, fontWeight: FontWeight.bold)), Expanded( child: Text("${value ?? '-'}", style: GoogleFonts.poppins(fontSize: 12, color: Colors.black))), ], ), ); } Widget _actionButton( {required String label, required IconData icon, required Color color, required VoidCallback onPressed}) { return SizedBox( height: 32, child: OutlinedButton.icon( style: OutlinedButton.styleFrom( side: BorderSide(color: color, width: 1.5), shape: const StadiumBorder(), padding: const EdgeInsets.symmetric(horizontal: 12)), onPressed: onPressed, icon: Icon(icon, size: 14, color: color), label: Text(label, style: GoogleFonts.poppins( fontSize: 11, fontWeight: FontWeight.bold, color: color)), ), ); } }