import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:google_fonts/google_fonts.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../layout/main_layout.dart'; import '../pages/petugas_drawer.dart'; import '../pages/login_page.dart'; import '../pages/tambah_petugas.dart'; import '../pages/edit_petugas.dart'; class DataPetugasPage extends StatefulWidget { const DataPetugasPage({super.key}); @override State createState() => _DataPetugasPageState(); } class _DataPetugasPageState extends State { final TextEditingController _searchController = TextEditingController(); Timer? _debounce; int _rowsPerPage = 10; int _currentPage = 0; int _totalData = 0; List> _allData = []; bool _isLoading = false; bool _isAuthorized = false; final String baseUrl = "http://ta.myhost.id/E31230549/mposyandu_api/petugas/get_users.php"; final String deleteUrl = "http://ta.myhost.id/E31230549/mposyandu_api/petugas/delete_petugas.php"; @override void initState() { super.initState(); checkLogin(); } @override void dispose() { _debounce?.cancel(); _searchController.dispose(); super.dispose(); } 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, ); return; } setState(() => _isAuthorized = true); await fetchUsers(); } Future fetchUsers() async { if (!_isAuthorized || !mounted) return; setState(() => _isLoading = true); try { final url = Uri.parse(baseUrl).replace(queryParameters: { "page": (_currentPage + 1).toString(), "limit": _rowsPerPage.toString(), "search": _searchController.text.trim(), }); final response = await http.get(url); if (response.statusCode == 200) { final decoded = json.decode(response.body); if (decoded["success"] == true) { setState(() { _allData = List>.from(decoded["data"] ?? []); _totalData = decoded["total"] ?? 0; }); } } } catch (e) { debugPrint("ERROR FETCH: $e"); } finally { if (mounted) setState(() => _isLoading = false); } } // --- LOGIKA SEMBUNYIKAN DESA/DUSUN BERDASARKAN ROLE --- void _showDetailDialog(Map data) { // Ambil role dan ubah ke lowercase agar pengecekan lebih akurat String role = (data["role"] ?? "").toString().toLowerCase(); bool isStaff = role == "admin" || role == "bidan"; showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)), title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("Detail Petugas", style: GoogleFonts.poppins( fontWeight: FontWeight.bold, fontSize: 16)), IconButton( icon: const Icon(Icons.close, color: Colors.red), onPressed: () => Navigator.pop(context)), ], ), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ _detailItem("Email", data["email"]), // Tampilkan Desa & Dusun HANYA jika role BUKAN admin/bidan if (!isStaff) ...[ _detailItem("Desa", data["nama_desa"]), _detailItem("Dusun", data["nama_dusun"]), ], _detailItem("No HP", data["no_hp"]), ], ), ), ), ); } Widget _detailItem(String label, dynamic value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: GoogleFonts.poppins(fontSize: 10, color: Colors.grey[600])), const SizedBox(height: 2), Text(value?.toString() ?? "-", style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.w500, color: Colors.black87)), const Divider(thickness: 0.5), ], ), ); } Future _deletePetugas(String id) async { final confirm = await showDialog( context: context, builder: (context) => AlertDialog( title: Text("Konfirmasi", style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.bold)), content: const Text("Yakin ingin menghapus petugas ini?"), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text("Batal")), ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom(backgroundColor: Colors.red), child: const Text("Hapus", style: TextStyle(color: Colors.white)), ), ], ), ); if (confirm != true) return; try { final res = await http.post(Uri.parse(deleteUrl), body: {"id": id}); if (json.decode(res.body)["success"]) fetchUsers(); } catch (e) { debugPrint("Delete error: $e"); } } @override Widget build(BuildContext context) { int totalPages = (_totalData / _rowsPerPage).ceil(); if (totalPages == 0) totalPages = 1; return MainLayout( title: "", drawer: const DrawerPetugas(), body: Padding( padding: const EdgeInsets.all(16), child: Column( children: [ Text("Data Petugas", style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), Row( children: [ Expanded( child: TextField( controller: _searchController, style: GoogleFonts.poppins(fontSize: 13), decoration: InputDecoration( hintText: "Cari nama...", prefixIcon: const Icon(Icons.search, size: 20), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10)), contentPadding: const EdgeInsets.symmetric(horizontal: 10), ), onChanged: (v) { _debounce?.cancel(); _debounce = Timer(const Duration(milliseconds: 500), () { _currentPage = 0; fetchUsers(); }); }, ), ), const SizedBox(width: 8), ElevatedButton( onPressed: () async { final res = await Navigator.push( context, MaterialPageRoute( builder: (_) => const TambahPetugasPage())); if (res == true) fetchUsers(); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, padding: const EdgeInsets.all(12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), ), child: const Icon(Icons.add, color: Colors.white), ) ], ), const SizedBox(height: 16), Expanded( child: _isLoading ? const Center(child: CircularProgressIndicator()) : _allData.isEmpty ? const Center(child: Text("Data tidak ditemukan")) : ListView.builder( itemCount: _allData.length, itemBuilder: (context, index) { final item = _allData[index]; return Card( elevation: 0, margin: const EdgeInsets.only(bottom: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: BorderSide( color: Colors.grey.shade300, width: 1), ), child: Padding( padding: const EdgeInsets.all(12), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(item["nama"] ?? "", style: GoogleFonts.poppins( fontWeight: FontWeight.bold, fontSize: 14)), const SizedBox(height: 4), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2), decoration: BoxDecoration( color: Colors.blue.withOpacity(0.1), borderRadius: BorderRadius.circular(6), ), child: Text(item["role"] ?? "", style: GoogleFonts.poppins( fontSize: 11, color: Colors.blue, fontWeight: FontWeight.w600)), ), ], ), ), _actionButton(Icons.visibility, Colors.blue, () => _showDetailDialog(item)), const SizedBox(width: 8), _actionButton(Icons.edit, Colors.orange, () async { final res = await Navigator.push( context, MaterialPageRoute( builder: (_) => EditPetugasPage(data: item))); if (res == true) fetchUsers(); }), const SizedBox(width: 8), _actionButton( Icons.delete, Colors.red, () => _deletePetugas( item["id"].toString())), ], ), ), ); }, ), ), 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--); fetchUsers(); }, ), IconButton( icon: const Icon(Icons.chevron_right), onPressed: _currentPage >= totalPages - 1 ? null : () { setState(() => _currentPage++); fetchUsers(); }, ), ], ) ], ) ], ), ), ); } Widget _actionButton(IconData icon, Color color, VoidCallback onTap) { return Material( color: Colors.transparent, child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(8), child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all(color: color, width: 1.5), ), child: Icon(icon, color: color, size: 18), ), ), ); } }