import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import '../layout/main_layout.dart'; import 'bidan_drawer.dart'; // Import file crud import '../bidan/crud_imunisasi/tambah_imunisasi.dart'; import '../bidan/crud_imunisasi/edit_imunisasi.dart'; import '../bidan/crud_imunisasi/data_imunisasi_balita.dart'; // Import Dashboard Bidan agar navigasi berfungsi import '../bidan/dashboard_bidan.dart'; class DataImunisasiPage extends StatefulWidget { const DataImunisasiPage({super.key}); @override State createState() => _DataImunisasiPageState(); } class _DataImunisasiPageState extends State { List masterImunisasi = []; String _searchQuery = ""; bool isLoading = true; // Variabel Pagination int _currentPage = 0; final int _rowsPerPage = 10; // Endpoint API final String baseMaster = "http://ta.myhost.id/E31230549/mposyandu_api/imunisasi/get_master_imunisasi.php"; final String urlDelete = "http://ta.myhost.id/E31230549/mposyandu_api/imunisasi/hapus_imunisasi.php"; @override void initState() { super.initState(); fetchMasterData(); } Future fetchMasterData() async { try { final resMaster = await http.get(Uri.parse(baseMaster)); if (mounted) { setState(() { masterImunisasi = jsonDecode(resMaster.body)["data"] ?? []; isLoading = false; }); } } catch (e) { if (mounted) setState(() => isLoading = false); } } Future _deleteData(String id) async { try { final response = await http.post( Uri.parse(urlDelete), body: {"id": id}, ); final data = jsonDecode(response.body); if (data['status'] == 'success') { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(data['message'] ?? "Data berhasil dihapus"), backgroundColor: Colors.blue, ), ); fetchMasterData(); } else { throw data['message'] ?? "Gagal menghapus data"; } } catch (e) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Kesalahan: $e"), backgroundColor: Colors.red), ); } } void _showDeleteDialog(Map item) { showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)), title: Text("Konfirmasi Hapus", style: GoogleFonts.poppins(fontWeight: FontWeight.bold, fontSize: 16)), content: Text( "Apakah Anda yakin ingin menghapus '${item['nama_imunisasi']}'?", style: GoogleFonts.poppins(fontSize: 13)), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text("Batal", style: GoogleFonts.poppins(color: Colors.grey)), ), OutlinedButton( onPressed: () { Navigator.pop(context); _deleteData(item['id'].toString()); }, style: OutlinedButton.styleFrom( side: const BorderSide(color: Colors.red), shape: const StadiumBorder(), ), child: Text("Hapus", style: GoogleFonts.poppins( color: Colors.red, fontWeight: FontWeight.bold)), ), ], ), ); } List get _filteredMaster { return masterImunisasi.where((item) { final nama = item["nama_imunisasi"].toString().toLowerCase(); final ket = item["keterangan"].toString().toLowerCase(); final query = _searchQuery.toLowerCase(); return nama.contains(query) || ket.contains(query); }).toList(); } List get _paginatedData { final start = _currentPage * _rowsPerPage; final end = start + _rowsPerPage; if (start >= _filteredMaster.length) return []; return _filteredMaster.sublist( start, end > _filteredMaster.length ? _filteredMaster.length : end, ); } @override Widget build(BuildContext context) { final totalPages = (_filteredMaster.length / _rowsPerPage).ceil() == 0 ? 1 : (_filteredMaster.length / _rowsPerPage).ceil(); return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) async { if (didPop) return; Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (_) => const DashboardBidanPage()), (route) => false, ); }, child: MainLayout( title: "", drawer: const BidanDrawer(), body: isLoading ? const Center(child: CircularProgressIndicator()) : Column( children: [ Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( children: [ Text( "Data Jenis Imunisasi", style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 15), // --- INPUT CARI --- Center( child: Container( constraints: const BoxConstraints(maxWidth: 850), child: TextField( onChanged: (value) => setState(() { _searchQuery = value; _currentPage = 0; }), style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( hintText: "Cari nama atau keterangan...", hintStyle: GoogleFonts.poppins(fontSize: 12), prefixIcon: const Icon(Icons.search, size: 20), filled: true, fillColor: Colors.grey[50], border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: Colors.grey[300]!), ), contentPadding: const EdgeInsets.symmetric(vertical: 8), ), ), ), ), const SizedBox(height: 20), // --- TABEL DENGAN DATATABLE --- Center( child: Container( constraints: const BoxConstraints(maxWidth: 850), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(12), child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: DataTable( headingRowColor: MaterialStateProperty.all(Colors.blue), columnSpacing: 25, columns: [ _buildDataColumn("Nama Imunisasi"), _buildDataColumn("Min"), _buildDataColumn("Max"), _buildDataColumn("Keterangan"), _buildDataColumn("Aksi"), ], rows: _paginatedData.isEmpty ? [ DataRow(cells: [ DataCell(Text( "Data tidak ditemukan", style: GoogleFonts.poppins( fontSize: 12))), const DataCell(SizedBox()), const DataCell(SizedBox()), const DataCell(SizedBox()), const DataCell(SizedBox()), ]) ] : _paginatedData.map((item) { return DataRow(cells: [ DataCell(Text( item["nama_imunisasi"] ?? "-", style: GoogleFonts.poppins( fontSize: 12))), DataCell(Text( "${item["usia_min"]} Bln", style: GoogleFonts.poppins( fontSize: 12))), DataCell(Text( "${item["usia_max"]} Bln", style: GoogleFonts.poppins( fontSize: 12))), DataCell( Container( constraints: const BoxConstraints( maxWidth: 180), child: Text( item["keterangan"] ?? "-", style: GoogleFonts.poppins( fontSize: 12), overflow: TextOverflow.ellipsis, maxLines: 2, ), ), ), DataCell( Row( children: [ IconButton( icon: const Icon( Icons.edit, color: Colors.orange, size: 20), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => EditImunisasiPage( data: item), ), ).then((value) { if (value == true) fetchMasterData(); }); }, ), IconButton( icon: const Icon( Icons.delete, color: Colors.red, size: 20), onPressed: () => _showDeleteDialog( item), ), ], ), ), ]); }).toList(), ), ), ), ), ), const SizedBox(height: 25), // --- BUTTON ACTION --- Center( child: Container( constraints: const BoxConstraints(maxWidth: 850), child: Row( children: [ Expanded( child: _actionBtnLonjong( Icons.add, "Tambah Jenis", Colors.blue, () { Navigator.push( context, MaterialPageRoute( builder: (context) => const TambahImunisasiPage(), ), ).then((_) => fetchMasterData()); }), ), const SizedBox(width: 12), Expanded( child: _actionBtnLonjong( Icons.visibility, "Imunisasi Balita", Colors.deepPurple, () { Navigator.push( context, MaterialPageRoute( builder: (context) => const DataImunisasiBalitaPage(), ), ); }), ), ], ), ), ), ], ), ), ), // --- PAGINATION --- Container( width: double.infinity, color: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 10), decoration: BoxDecoration( border: Border(top: BorderSide(color: Colors.grey[200]!)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("Halaman ${_currentPage + 1} dari $totalPages", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500)), 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++), ), ], ), ], ), ), ], ), ), ); } DataColumn _buildDataColumn(String label) { return DataColumn( label: Text( label, style: GoogleFonts.poppins( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 13, ), ), ); } Widget _actionBtnLonjong( IconData icon, String label, Color color, VoidCallback onTap) { return OutlinedButton.icon( onPressed: onTap, icon: Icon(icon, size: 18, color: color), style: OutlinedButton.styleFrom( side: BorderSide(color: color, width: 1.5), shape: const StadiumBorder(), padding: const EdgeInsets.symmetric(vertical: 14), ), label: Text( label, style: GoogleFonts.poppins( fontSize: 12, color: color, fontWeight: FontWeight.bold), ), ); } }