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 '../layout/main_layout.dart'; import 'kader_drawer.dart'; import '../pages/login_page.dart'; import '../kader/crud_pemeriksaan/tambah_pemeriksaan.dart'; import '../kader/crud_pemeriksaan/riwayat_pemeriksaan_balita.dart'; import '../kader/dashboard_kader.dart'; class DataPemeriksaanBalitaPage extends StatefulWidget { const DataPemeriksaanBalitaPage({super.key}); @override State createState() => _DataPemeriksaanBalitaPageState(); } class _DataPemeriksaanBalitaPageState extends State { List> _dataBalita = []; List> _allDataBalita = []; bool _loading = true; bool _checkingLogin = true; String? _dusunId; int _currentPage = 0; final int _rowsPerPage = 5; 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" ]; String hari = dt.day.toString().padLeft(2, '0'); String bulan = bulanIndo[dt.month]; String tahun = dt.year.toString(); return "$hari $bulan $tahun"; } catch (e) { return tanggal; } } 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 "-"; } } @override void initState() { super.initState(); _checkLogin(); } Future _checkLogin() async { try { final prefs = await SharedPreferences.getInstance(); final isLogin = prefs.getBool('isLogin') ?? false; if (!isLogin) { if (!mounted) return; Navigator.pushReplacement( context, MaterialPageRoute(builder: (_) => const LoginPage()), ); return; } dynamic rawDusunId = prefs.get('dusun_id'); if (mounted) { setState(() { _dusunId = rawDusunId?.toString(); _checkingLogin = false; }); } _fetchDataBalita(); } catch (e) { debugPrint("Error Check Login: $e"); if (mounted) setState(() => _checkingLogin = false); } } Future _fetchDataBalita() async { if (_dusunId == null || _dusunId == "null" || _dusunId == "0") { setState(() => _loading = false); return; } setState(() => _loading = true); final url = Uri.parse( 'http://ta.myhost.id/E31230549/mposyandu_api/pemeriksaan_balita/get_pemeriksaan_balita.php?dusun_id=$_dusunId', ); try { final response = await http.get(url).timeout(const Duration(seconds: 10)); 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["tanggal_lahir"].toString().isNotEmpty && item["tanggal_lahir"] != "-") { item["usia_formatted"] = hitungUsia(item["tanggal_lahir"].toString()); item["tgl_lahir_indo"] = _formatTanggalIndo(item["tanggal_lahir"].toString()); } else { item["usia_formatted"] = "-"; item["tgl_lahir_indo"] = "-"; } item["bb_formatted"] = "${item["bb"] ?? '-'} kg"; item["tb_formatted"] = "${item["tb"] ?? '-'} cm"; item["lk_formatted"] = "${item["lk"] ?? '-'} cm"; } _allDataBalita = data; _dataBalita = data; _loading = false; }); } else { setState(() { _dataBalita = []; _loading = false; }); } } else { setState(() => _loading = false); } } catch (e) { debugPrint("ERROR FETCH: $e"); setState(() => _loading = false); } } List> get _paginatedData { if (_dataBalita.isEmpty) return []; final start = _currentPage * _rowsPerPage; final end = start + _rowsPerPage; if (start >= _dataBalita.length) return []; return _dataBalita.sublist( start, end > _dataBalita.length ? _dataBalita.length : end, ); } @override Widget build(BuildContext context) { if (_checkingLogin) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } final totalPages = _dataBalita.isEmpty ? 1 : (_dataBalita.length / _rowsPerPage).ceil(); return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) async { if (didPop) return; Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (_) => const DashboardKaderPage()), (route) => false, ); }, child: MainLayout( title: "", drawer: const KaderDrawer(), body: _loading ? const Center(child: CircularProgressIndicator()) : Padding( padding: const EdgeInsets.all(16), child: Column( children: [ Center( child: Text( "Data Pemeriksaan Balita", style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ), const SizedBox(height: 12), TextField( style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( hintText: "Cari nama balita...", hintStyle: GoogleFonts.poppins(fontSize: 12), prefixIcon: const Icon(Icons.search, size: 20), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), ), contentPadding: const EdgeInsets.symmetric(vertical: 8), ), onChanged: (value) { setState(() { _dataBalita = _allDataBalita .where((b) => (b['nama_balita'] ?? '') .toLowerCase() .contains(value.toLowerCase())) .toList(); _currentPage = 0; }); }, ), const SizedBox(height: 15), Expanded( child: _dataBalita.isEmpty ? Center( child: Text( "Tidak ada data pemeriksaan", style: GoogleFonts.poppins(fontSize: 12), ), ) : ListView.builder( itemCount: _paginatedData.length, itemBuilder: (context, index) { final balita = _paginatedData[index]; bool isLolos = balita["status"] == 'lolos'; String? statusHadir = balita["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( balita["nama_balita"] ?? "-", style: GoogleFonts.poppins( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14, ), ), ), Row( children: [ // Badge Status Hadir (Hanya 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, ), ), ), // Badge Lolos 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: 6), _rowWhite("Orang Tua", balita["ibu_suami"]), _rowWhite("Jenis Kelamin", balita["jk_formatted"]), _rowWhite("Tgl Lahir", balita["tgl_lahir_indo"]), _rowWhite("Usia", balita["usia_formatted"]), _rowWhite( "Desa", balita["nama_desa"]), _rowWhite( "Dusun", balita["nama_dusun"]), _rowWhite("Alamat", balita["alamat_detail"]), ], ), ), Container( width: double.infinity, padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Riwayat Pemeriksaan Terakhir", style: GoogleFonts.poppins( fontWeight: FontWeight.bold, fontSize: 12, color: Colors.black87, ), ), const Divider(), _riwayatList(balita), const SizedBox(height: 12), Row( children: [ Expanded( child: OutlinedButton.icon( onPressed: () async { if (isLolos) { ScaffoldMessenger.of( context) .showSnackBar( const SnackBar( content: Text( "Balita ini sudah lolos pemeriksaan, penginputan dinonaktifkan."), backgroundColor: Colors.orange, ), ); return; } await Navigator.push( context, MaterialPageRoute( builder: (_) => TambahPemeriksaanBalitaPage( balita: balita), ), ); _fetchDataBalita(); }, icon: const Icon(Icons.add, size: 16), label: const Text("Input"), style: OutlinedButton .styleFrom( foregroundColor: isLolos ? Colors.grey : Colors.blue, side: BorderSide( color: isLolos ? Colors.grey : Colors.blue, width: 1.5), shape: const StadiumBorder(), textStyle: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight .bold), padding: const EdgeInsets .symmetric( vertical: 10), ), ), ), const SizedBox(width: 10), Expanded( child: OutlinedButton.icon( onPressed: () async { await Navigator.push( context, MaterialPageRoute( builder: (_) => RiwayatPemeriksaanBalitaPage( idBalita: int.tryParse( balita["id_balita"].toString()) ?? 0), ), ); _fetchDataBalita(); }, icon: const Icon( Icons.history, size: 16), label: const Text("Riwayat"), style: OutlinedButton .styleFrom( foregroundColor: Colors.deepPurple, side: const BorderSide( color: Colors.deepPurple, width: 1.5), shape: const StadiumBorder(), textStyle: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight .bold), padding: const EdgeInsets .symmetric( vertical: 10), ), ), ), ], ), ], ), ), ], ), ); }, ), ), // PAGINATION Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( border: Border( top: BorderSide(color: Colors.grey.shade200))), 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, 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 _rowWhite(String label, dynamic value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 110, child: Text( label, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.white), ), ), const Text(" : ", style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)), Expanded( child: Text( "${value ?? '-'}", style: GoogleFonts.poppins( fontSize: 12, color: Colors.white, fontWeight: FontWeight.w400), ), ), ], ), ); } Widget _riwayatList(Map balita) { final items = { "Tgl Periksa": _formatTanggalIndo(balita["tanggal_pemeriksaan"]), "Berat Badan": balita["bb_formatted"], "Tinggi Badan": balita["tb_formatted"], "Lingkar Kepala": balita["lk_formatted"], "Imunisasi": balita["imunisasi"], "Vitamin A": balita["vitamin_a"], "PMT": balita["pmt"], "Catatan": balita["catatan"], }; return Column( children: items.entries.map((entry) { return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 110, child: Text( entry.key, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.black87), ), ), const Text(" : ", style: TextStyle(fontWeight: FontWeight.bold)), Expanded( child: Text( "${entry.value ?? '-'}", style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), ), ), ], ), ); }).toList(), ); } }