import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; import '../layout/main_layout.dart'; import 'kader_drawer.dart'; import '../pages/login_page.dart'; import 'crud_ibu_hamil/tambah_ibu_hamil.dart'; import 'crud_ibu_hamil/edit_ibu_hamil.dart'; import '../kader/dashboard_kader.dart'; class DataIbuHamilPage extends StatefulWidget { const DataIbuHamilPage({super.key}); @override State createState() => _DataIbuHamilPageState(); } class _DataIbuHamilPageState extends State { List _data = []; List _filteredData = []; bool _isLoading = true; int _currentPage = 0; final int _rowsPerPage = 5; final TextEditingController _searchC = TextEditingController(); Timer? _debounce; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { _checkLogin(); _fetchData(); }); _searchC.addListener(_onSearchChanged); } @override void dispose() { _searchC.dispose(); _debounce?.cancel(); super.dispose(); } // Fungsi untuk menghitung usia kehamilan berdasarkan HPHT String _hitungUsiaKehamilan(String? hphtString) { if (hphtString == null || hphtString.isEmpty || hphtString == "-" || hphtString == "0000-00-00") return "-"; try { DateTime hpht = DateTime.parse(hphtString); DateTime sekarang = DateTime.now(); // Hitung selisih hari int totalHari = sekarang.difference(hpht).inDays; if (totalHari < 0) return "Belum Hamil"; int minggu = totalHari ~/ 7; int sisaHari = totalHari % 7; if (minggu >= 42) return "Sudah Waktunya Lahir"; return "$minggu Minggu $sisaHari Hari"; } catch (e) { return "-"; } } // Fungsi Helper untuk menentukan warna berdasarkan status Color _getStatusColor(String status) { switch (status.toLowerCase()) { case 'keguguran': return Colors.red; case 'melahirkan': return Colors.blue; case 'aktif': default: return Colors.green; } } String _formatTanggalIndo(String? tanggal) { if (tanggal == null || tanggal.isEmpty || tanggal == "-" || tanggal == "0000-00-00") return "-"; try { DateTime dt = DateTime.parse(tanggal); List bulanIndo = [ "", "Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember" ]; return "${dt.day.toString().padLeft(2, '0')} ${bulanIndo[dt.month]} ${dt.year}"; } catch (e) { return tanggal; } } void _onSearchChanged() { if (_debounce?.isActive ?? false) _debounce!.cancel(); _debounce = Timer(const Duration(milliseconds: 400), () { final keyword = _searchC.text.toLowerCase(); setState(() { _currentPage = 0; _filteredData = _data.where((item) { final namaIbu = (item["nama_ibu"] ?? "").toString().toLowerCase(); final status = (item["status"] ?? "").toString().toLowerCase(); return namaIbu.contains(keyword) || status.contains(keyword); }).toList(); }); }); } Future _checkLogin() async { final prefs = await SharedPreferences.getInstance(); final isLogin = prefs.getBool('isLogin') ?? false; if (!isLogin) { if (!mounted) return; Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (_) => const LoginPage(fromGuard: true)), (route) => false, ); } } Future _fetchData() async { setState(() => _isLoading = true); try { final prefs = await SharedPreferences.getInstance(); final rawDusunId = prefs.get('dusun_id'); String dusunId = rawDusunId?.toString() ?? ""; final url = Uri.parse( "http://ta.myhost.id/E31230549/mposyandu_api/ibu_hamil/get_ibu_hamil.php?dusun_id=$dusunId"); final response = await http.get(url); final jsonData = json.decode(response.body); if (jsonData["success"] == true) { setState(() { _data = jsonData["data"]; _filteredData = _data; _isLoading = false; }); } else { setState(() { _data = []; _filteredData = []; _isLoading = false; }); } } catch (e) { debugPrint("ERROR GET IBU HAMIL: $e"); setState(() => _isLoading = false); } } Future _deleteData(String id) async { try { final url = Uri.parse( "http://ta.myhost.id/E31230549/mposyandu_api/ibu_hamil/hapus_ibu_hamil.php"); final response = await http.post(url, body: {"id": id}); final data = json.decode(response.body); if (data["success"] == true) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Data berhasil dihapus"))); _fetchData(); } } catch (e) { debugPrint("Gagal hapus: $e"); } } List get _paginatedData { final start = _currentPage * _rowsPerPage; final end = start + _rowsPerPage; if (start >= _filteredData.length) return []; return _filteredData.sublist( start, end > _filteredData.length ? _filteredData.length : end); } @override Widget build(BuildContext context) { final totalPages = _filteredData.isEmpty ? 1 : (_filteredData.length / _rowsPerPage).ceil(); return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { if (didPop) return; Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (_) => const DashboardKaderPage()), (route) => false, ); }, child: MainLayout( title: "", drawer: const KaderDrawer(), body: Padding( padding: const EdgeInsets.all(16), child: Column( children: [ Center( child: Text("Data Ibu Hamil", style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold)), ), const SizedBox(height: 16), Row( children: [ Expanded( child: TextField( controller: _searchC, decoration: InputDecoration( hintText: "Cari nama...", prefixIcon: const Icon(Icons.search), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10)), ), ), ), const SizedBox(width: 10), OutlinedButton.icon( onPressed: () async { await Navigator.push( context, MaterialPageRoute( builder: (_) => const TambahIbuHamilPage())); _fetchData(); }, icon: const Icon(Icons.add, size: 18), label: const Text("Tambah"), style: OutlinedButton.styleFrom( foregroundColor: Colors.blue, side: const BorderSide(color: Colors.blue), shape: const StadiumBorder(), ), ), ], ), const SizedBox(height: 20), Expanded( child: _isLoading ? const Center(child: CircularProgressIndicator()) : _filteredData.isEmpty ? Center( child: Text( "Tidak Ada Data Ibu Hamil", style: GoogleFonts.poppins( fontSize: 16, color: Colors.black, fontWeight: FontWeight.w500, ), ), ) : ListView.builder( itemCount: _paginatedData.length, itemBuilder: (context, index) { final item = _paginatedData[index]; final String status = item["status"] ?? "aktif"; Color headerColor = _getStatusColor(status); return Container( margin: const EdgeInsets.only(bottom: 14), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: const [ BoxShadow( color: Colors.black12, blurRadius: 6) ], ), child: Column( children: [ Container( width: double.infinity, padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: headerColor, borderRadius: const BorderRadius.only( topLeft: Radius.circular(12), topRight: Radius.circular(12)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(item["nama_ibu"] ?? "-", style: GoogleFonts.poppins( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white)), Text(status.toUpperCase(), style: GoogleFonts.poppins( fontSize: 10, fontWeight: FontWeight.w800, color: Colors.white)), ], ), ), Padding( padding: const EdgeInsets.all(12), child: Column( children: [ _row("Nama Suami", item["nama_suami"] ?? "-"), _row("HPHT", _formatTanggalIndo(item["hpht"])), // MENAMPILKAN USIA KEHAMILAN YANG DIHITUNG OTOMATIS _row( "Usia Kehamilan", _hitungUsiaKehamilan( item["hpht"])), _row("HPL", _formatTanggalIndo(item["hpl"])), _row( "Persalinan Sblmnya", _formatTanggalIndo(item[ "tanggal_persalinan_sebelumnya"])), _row( "Gravida (G)", item["gravida"]?.toString() ?? "-"), _row("Para (P)", item["para"]?.toString() ?? "-"), _row( "Abortus (A)", item["abortus"]?.toString() ?? "-"), _row("Hidup", item["hidup"]?.toString() ?? "-"), _row("Pembiayaan", item["pembiayaan"] ?? "-"), const Divider(), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ _smallButton( text: "Edit", icon: Icons.edit, color: Colors.orange, onPressed: () async { final res = await Navigator.push( context, MaterialPageRoute( builder: (_) => EditIbuHamilPage( data: item))); if (res == true) _fetchData(); }, ), const SizedBox(width: 8), _smallButton( text: "Hapus", icon: Icons.delete, color: Colors.red, onPressed: () => _showDeleteDialog( item["id"].toString()), ), ], ) ], ), ) ], ), ); }, ), ), if (_filteredData.isNotEmpty) _buildPagination(totalPages), ], ), ), ), ); } void _showDeleteDialog(String id) { showDialog( context: context, builder: (_) => AlertDialog( title: const Text("Hapus Data?"), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text("Batal")), TextButton( onPressed: () { Navigator.pop(context); _deleteData(id); }, child: const Text("Hapus", style: TextStyle(color: Colors.red))), ], ), ); } Widget _buildPagination(int totalPages) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("Hal ${_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 _smallButton( {required String text, required IconData icon, required Color color, required VoidCallback onPressed}) { return OutlinedButton.icon( onPressed: onPressed, icon: Icon(icon, size: 14, color: color), label: Text(text, style: GoogleFonts.poppins( fontSize: 11, fontWeight: FontWeight.bold, color: color)), style: OutlinedButton.styleFrom( side: BorderSide(color: color), shape: const StadiumBorder()), ); } Widget _row(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Row( children: [ SizedBox( width: 130, child: Text(label, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600))), const Text(" : "), Expanded( child: Text(value, style: GoogleFonts.poppins(fontSize: 12))), ], ), ); } }