import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'edit_gizi_balita.dart'; class RiwayatGiziBalitaPage extends StatefulWidget { final Map balita; const RiwayatGiziBalitaPage({super.key, required this.balita}); @override State createState() => _RiwayatGiziBalitaPageState(); } class _RiwayatGiziBalitaPageState extends State { List> _riwayatGizi = []; List> _filteredRiwayatGizi = []; bool _isLoading = true; final TextEditingController _searchController = TextEditingController(); // Variabel Pagination int _currentPage = 0; final int _rowsPerPage = 5; @override void initState() { super.initState(); fetchRiwayat(); } // Logika mendapatkan data per halaman List> get _paginatedData { if (_filteredRiwayatGizi.isEmpty) return []; final start = _currentPage * _rowsPerPage; final end = start + _rowsPerPage; if (start >= _filteredRiwayatGizi.length) return []; return _filteredRiwayatGizi.sublist( start, end > _filteredRiwayatGizi.length ? _filteredRiwayatGizi.length : end, ); } String formatTanggal(String? tgl) { if (tgl == null || tgl == "-" || tgl.isEmpty) return "-"; try { DateTime dt = DateTime.parse(tgl); 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 tgl; } } void _filterData(String query) { setState(() { _filteredRiwayatGizi = _riwayatGizi.where((data) { final tanggal = data["tanggal_pemeriksaan"]?.toString().toLowerCase() ?? ""; return tanggal.contains(query.toLowerCase()); }).toList(); _currentPage = 0; // Reset ke halaman pertama saat mencari }); } String hitungUsia(String? tglLahir) { if (tglLahir == null || tglLahir == "-" || tglLahir.isEmpty) return "-"; try { DateTime lahir = DateTime.parse(tglLahir); DateTime sekarang = DateTime.now(); int bulan = (sekarang.year - lahir.year) * 12 + sekarang.month - lahir.month; return "$bulan Bulan"; } catch (e) { return "-"; } } Future fetchRiwayat() async { setState(() => _isLoading = true); try { final idBalita = widget.balita['id']; final response = await http.get( Uri.parse( "http://ta.myhost.id/E31230549/mposyandu_api/gizi_balita/get_riwayat_gizi_balita.php?id_balita=$idBalita"), ); if (response.statusCode == 200) { final data = json.decode(response.body); setState(() { _riwayatGizi = List>.from(data); _filteredRiwayatGizi = _riwayatGizi; _isLoading = false; }); } else { throw Exception("Gagal load data"); } } catch (e) { setState(() => _isLoading = false); } } Future hapusData(String idGizi) async { try { final response = await http.post( Uri.parse( "http://ta.myhost.id/E31230549/mposyandu_api/gizi_balita/hapus_gizi_balita.php"), headers: {"Content-Type": "application/json"}, body: jsonEncode({"id_gizi": idGizi}), ); final res = json.decode(response.body); if (res["success"] == true) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Data berhasil dihapus"))); fetchRiwayat(); } } catch (e) { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text("Error: $e"))); } } @override Widget build(BuildContext context) { final totalPages = _filteredRiwayatGizi.isEmpty ? 1 : (_filteredRiwayatGizi.length / _rowsPerPage).ceil(); return Scaffold( backgroundColor: Colors.grey[50], appBar: AppBar( backgroundColor: Colors.blue, elevation: 0, iconTheme: const IconThemeData(color: Colors.white), title: Text("", style: GoogleFonts.poppins( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600)), ), body: Padding( padding: const EdgeInsets.all(16), child: Column( children: [ Center( child: Text("Data Riwayat Gizi Balita", style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black)), ), const SizedBox(height: 15), TextField( controller: _searchController, onChanged: _filterData, style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( hintText: "Cari berdasarkan tanggal (YYYY-MM-DD)...", hintStyle: GoogleFonts.poppins(fontSize: 12), prefixIcon: const Icon(Icons.search, size: 20), border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)), contentPadding: const EdgeInsets.symmetric(vertical: 8), ), ), const SizedBox(height: 20), Expanded( child: _isLoading ? const Center(child: CircularProgressIndicator()) : _filteredRiwayatGizi.isEmpty ? Center( child: Text("Data tidak ditemukan", style: GoogleFonts.poppins( fontSize: 12, color: Colors.grey))) : ListView.builder( itemCount: _paginatedData.length, itemBuilder: (context, index) { final gizi = _paginatedData[index]; return _buildCardIdentik(gizi); }, ), ), Container( padding: const EdgeInsets.symmetric(vertical: 8), child: 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), onPressed: _currentPage == 0 ? null : () => setState(() => _currentPage--), ), IconButton( icon: const Icon(Icons.chevron_right), onPressed: _currentPage >= totalPages - 1 ? null : () => setState(() => _currentPage++), ), ], ), ], ), ), ], ), ), ); } Widget _buildCardIdentik(Map data) { return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: const [ BoxShadow(color: Colors.black12, blurRadius: 8, offset: Offset(0, 4)) ], ), child: Column( children: [ Container( width: double.infinity, padding: const EdgeInsets.all(15), decoration: const BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.vertical(top: Radius.circular(12)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(widget.balita["nama"]?.toString() ?? "-", style: GoogleFonts.poppins( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14)), const Divider(color: Colors.white54), _rowWhite("Orang Tua", widget.balita["nama_orang_tua"]?.toString() ?? "-"), _rowWhite("Usia", hitungUsia(widget.balita["tanggal_lahir"]?.toString())), _rowWhite("Tgl Pemeriksaan", formatTanggal(data["tanggal_pemeriksaan"]?.toString())), _rowWhite("BB / TB / LK", "${data['bb'] ?? '-'}kg / ${data['tb'] ?? '-'}cm / ${data['lk'] ?? '-'}cm"), _rowWhite("Catatan Kader", data["catatan"]?.toString() ?? "-"), ], ), ), Container( width: double.infinity, padding: const EdgeInsets.all(15), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Detail Pemeriksaan", style: GoogleFonts.poppins( fontWeight: FontWeight.w600, fontSize: 12)), const SizedBox(height: 8), _rowGizi( "Z-Score BB/U", data["zscore_bb_u"]?.toString() ?? "-"), _rowGizi( "Z-Score TB/U", data["zscore_tb_u"]?.toString() ?? "-"), _rowGizi( "Z-Score BB/TB", data["zscore_bb_tb"]?.toString() ?? "-"), const Divider(), _rowStatus("Status Gizi", data), _rowGizi( "Tindak Lanjut", data["tindak_lanjut"]?.toString() ?? "-"), _rowGizi("Saran", data["saran"]?.toString() ?? "-"), const SizedBox(height: 12), Row( children: [ _stadiumButton(Icons.edit, "Edit", Colors.orange, () async { await Navigator.push( context, MaterialPageRoute( builder: (context) => EditGiziBalitaPage( dataGizi: { ...data, "nama": widget.balita["nama"], "tanggal_lahir": widget.balita["tanggal_lahir"], }, ), ), ); fetchRiwayat(); }), const SizedBox(width: 8), _stadiumButton(Icons.delete, "Hapus", Colors.red, () { _showDeleteDialog(data["id_gizi"].toString()); }), ], ) ], ), ), ], ), ); } Widget _rowWhite(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( children: [ SizedBox( width: 120, child: Text(label, style: GoogleFonts.poppins( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w600))), const Text(": ", style: TextStyle(color: Colors.white)), Expanded( child: Text(value, style: GoogleFonts.poppins(color: Colors.white, fontSize: 12))), ], ), ); } Widget _rowGizi(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( children: [ SizedBox( width: 120, child: Text(label, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.grey[800]))), const Text(": "), Expanded( child: Text(value, style: GoogleFonts.poppins(fontSize: 12, color: Colors.black))), ], ), ); } Widget _rowStatus(String label, Map data) { return Container( margin: const EdgeInsets.symmetric(vertical: 5), padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.orange[50], borderRadius: BorderRadius.circular(8)), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("$label :", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.orange[900])), const SizedBox(height: 4), Padding( padding: const EdgeInsets.only(left: 12), child: Column( children: [ _rowStatusDetail("BB / U", data["status_bbu"] ?? "-"), _rowStatusDetail("TB / U", data["status_tbu"] ?? "-"), _rowStatusDetail("BB / TB", data["status_bbtb"] ?? "-"), ], ), ), ], ), ); } Widget _rowStatusDetail(String indikator, String nilai) { return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Row( children: [ SizedBox( width: 65, child: Text( indikator, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.orange[900]), ), ), Text( " : ", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.orange[900]), ), Expanded( child: Text( nilai, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.bold, color: Colors.orange[900]), ), ), ], ), ); } Widget _stadiumButton( IconData icon, String text, Color color, VoidCallback onPressed) { return Expanded( child: OutlinedButton.icon( onPressed: onPressed, icon: Icon(icon, size: 14, color: color), label: Text(text, style: GoogleFonts.poppins( fontSize: 11, color: color, fontWeight: FontWeight.bold)), style: OutlinedButton.styleFrom( side: BorderSide(color: color), shape: const StadiumBorder(), padding: const EdgeInsets.symmetric(vertical: 8), ), ), ); } void _showDeleteDialog(String id) { showDialog( context: context, builder: (context) => AlertDialog( title: Text("Hapus Data", style: GoogleFonts.poppins(fontWeight: FontWeight.bold, fontSize: 16)), content: Text("Yakin ingin menghapus data pemeriksaan ini?", style: GoogleFonts.poppins(fontSize: 13)), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text("Batal")), TextButton( onPressed: () async { Navigator.pop(context); await hapusData(id); }, child: const Text("Hapus", style: TextStyle(color: Colors.red)), ), ], ), ); } }