MIF_E31230549/lib/kader/crud_pemeriksaan/riwayat_pemeriksaan_balita....

566 lines
24 KiB
Dart

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 '/../pages/login_page.dart';
import 'edit_pemeriksaan_balita.dart';
class RiwayatPemeriksaanBalitaPage extends StatefulWidget {
final int idBalita;
const RiwayatPemeriksaanBalitaPage({
super.key,
required this.idBalita,
});
@override
State<RiwayatPemeriksaanBalitaPage> createState() =>
_RiwayatPemeriksaanBalitaPageState();
}
class _RiwayatPemeriksaanBalitaPageState
extends State<RiwayatPemeriksaanBalitaPage> {
List<Map<String, dynamic>> _data = [];
List<Map<String, dynamic>> _allData = [];
bool _loading = true;
bool _checkingLogin = true;
int _currentPage = 0;
final int _rowsPerPage = 5;
@override
void initState() {
super.initState();
_checkLogin();
}
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 "-";
}
}
String _formatTanggalIndo(String? tanggal) {
if (tanggal == null || tanggal.isEmpty || tanggal == "-") return "-";
try {
DateTime dt = DateTime.parse(tanggal);
List<String> bulanIndo = [
"",
"Januari",
"Februari",
"Maret",
"April",
"Mei",
"Juni",
"Juli",
"Agustus",
"September",
"Oktober",
"November",
"Desember"
];
return "${dt.day} ${bulanIndo[dt.month]} ${dt.year}";
} catch (e) {
return tanggal;
}
}
Future<void> _checkLogin() async {
final prefs = await SharedPreferences.getInstance();
final isLogin = prefs.getBool('isLogin') ?? false;
if (!isLogin) {
if (!mounted) return;
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const LoginPage()),
);
return;
}
setState(() => _checkingLogin = false);
_fetchData();
}
Future<void> _fetchData() async {
setState(() => _loading = true);
final url = Uri.parse(
'http://ta.myhost.id/E31230549/mposyandu_api/pemeriksaan_balita/get_riwayat_pemeriksaan_balita.php?id_balita=${widget.idBalita}',
);
try {
final response = await http.get(url);
if (response.statusCode == 200) {
final jsonData = json.decode(response.body);
if (jsonData["success"] == true) {
final List<Map<String, dynamic>> data =
List<Map<String, dynamic>>.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["usia_formatted"] = hitungUsia(item["tanggal_lahir"]);
item["tgl_lahir_formatted"] =
_formatTanggalIndo(item["tanggal_lahir"]);
} else {
item["usia_formatted"] = "-";
item["tgl_lahir_formatted"] = "-";
}
item["bb_formatted"] = "${item["bb"] ?? '-'} kg";
item["tb_formatted"] = "${item["tb"] ?? '-'} cm";
item["lk_formatted"] = "${item["lk"] ?? '-'} cm";
}
_allData = data;
_data = data;
_loading = false;
});
} else {
setState(() {
_data = [];
_loading = false;
});
}
}
} catch (e) {
debugPrint("ERROR FETCH: $e");
setState(() => _loading = false);
}
}
Future<void> _hapusData(int idPemeriksaan) async {
final confirm = await showDialog(
context: context,
builder: (c) => AlertDialog(
title: Text("Konfirmasi",
style:
GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.bold)),
content: Text("Yakin ingin menghapus data ini?",
style: GoogleFonts.poppins(fontSize: 12)),
actions: [
TextButton(
onPressed: () => Navigator.pop(c, false), child: Text("Batal")),
OutlinedButton(
onPressed: () => Navigator.pop(c, true),
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.red),
shape: const StadiumBorder()),
child: Text("Hapus",
style: GoogleFonts.poppins(
color: Colors.red,
fontSize: 12,
fontWeight: FontWeight.bold)),
),
],
),
);
if (confirm != true) return;
try {
final url = Uri.parse(
"http://ta.myhost.id/E31230549/mposyandu_api/pemeriksaan_balita/hapus_pemeriksaan_balita.php");
final response = await http
.post(url, body: {"id_pemeriksaan": idPemeriksaan.toString()});
final res = json.decode(response.body);
if (res["success"] == true) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Data berhasil dihapus")));
_fetchData();
}
} catch (e) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Gagal hapus: $e")));
}
}
List<Map<String, dynamic>> get _paginatedData {
if (_data.isEmpty) return [];
final start = _currentPage * _rowsPerPage;
final end = start + _rowsPerPage;
return _data.sublist(start, end > _data.length ? _data.length : end);
}
@override
Widget build(BuildContext context) {
if (_checkingLogin)
return const Scaffold(body: Center(child: CircularProgressIndicator()));
final totalPages = _data.isEmpty ? 1 : (_data.length / _rowsPerPage).ceil();
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
backgroundColor: Colors.blueAccent,
elevation: 0,
title: const Text(""),
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.pop(context)),
),
body: _loading
? const Center(child: CircularProgressIndicator())
: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Center(
child: Text("Data Riwayat Pemeriksaan",
style: GoogleFonts.poppins(
fontSize: 18, fontWeight: FontWeight.bold))),
const SizedBox(height: 15),
TextField(
style: GoogleFonts.poppins(fontSize: 12),
decoration: InputDecoration(
hintText: "Cari tanggal pemeriksaan....",
prefixIcon: const Icon(Icons.search, size: 20),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.symmetric(vertical: 8),
),
onChanged: (value) {
setState(() {
_data = _allData
.where((b) => (b['tanggal_pemeriksaan'] ?? '')
.toString()
.toLowerCase()
.contains(value.toLowerCase()))
.toList();
_currentPage = 0;
});
},
),
const SizedBox(height: 15),
Expanded(
child: _data.isEmpty
? Center(
child: Text("Tidak ada riwayat pemeriksaan",
style: GoogleFonts.poppins(fontSize: 12)))
: ListView.builder(
itemCount: _paginatedData.length,
itemBuilder: (context, index) {
final item = _paginatedData[index];
bool isLolos = item["status"] == 'lolos';
String? statusHadir = item["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(
item["nama_balita"] ?? "-",
style: GoogleFonts.poppins(
color: Colors.white,
fontWeight:
FontWeight.bold,
fontSize: 14),
),
),
Row(
children: [
// BADGE KEHADIRAN (Hanya muncul 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),
),
),
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: 4),
_rowHeader(
"Orang Tua", item["ibu_suami"]),
_rowHeader("Jenis Kelamin",
item["jk_formatted"]),
_rowHeader("Tgl Lahir",
item["tgl_lahir_formatted"]),
_rowHeader("Usia Saat Ini",
item["usia_formatted"]),
],
),
),
Container(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text("Hasil Pemeriksaan",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 12,
color: Colors.blueAccent)),
const Divider(),
_rowDetail(
"Tanggal Periksa",
_formatTanggalIndo(
item["tanggal_pemeriksaan"])),
_rowDetail("Berat Badan",
item["bb_formatted"]),
_rowDetail("Tinggi Badan",
item["tb_formatted"]),
_rowDetail("Lingkar Kepala",
item["lk_formatted"]),
_rowDetail(
"Imunisasi", item["imunisasi"]),
_rowDetail(
"Vitamin A", item["vitamin_a"]),
_rowDetail("PMT", item["pmt"]),
_rowDetail(
"Catatan", item["catatan"]),
const SizedBox(height: 10),
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
_actionButton(
label: "Edit",
icon: Icons.edit,
color: Colors.orange,
onPressed: () async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
EditPemeriksaanBalitaPage(
data: item)));
if (result == true)
_fetchData();
},
),
const SizedBox(width: 8),
_actionButton(
label: "Hapus",
icon: Icons.delete,
color: Colors.red,
onPressed: () => _hapusData(
int.parse(
item["id_pemeriksaan"]
.toString())),
),
],
),
],
),
),
],
),
);
},
),
),
const SizedBox(height: 10),
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 _rowHeader(String label, dynamic value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 1),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 95,
child: Text(label,
style: GoogleFonts.poppins(
fontSize: 11,
fontWeight: FontWeight.w600,
color: Colors.white))),
Text(" : ",
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.bold)),
Expanded(
child: Text("${value ?? '-'}",
style: GoogleFonts.poppins(
fontSize: 11,
color: Colors.white,
fontWeight: FontWeight.w400))),
],
),
);
}
Widget _rowDetail(String label, dynamic value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 105,
child: Text(label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.black87))),
Text(" : ",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.bold)),
Expanded(
child: Text("${value ?? '-'}",
style:
GoogleFonts.poppins(fontSize: 12, color: Colors.black))),
],
),
);
}
Widget _actionButton(
{required String label,
required IconData icon,
required Color color,
required VoidCallback onPressed}) {
return SizedBox(
height: 32,
child: OutlinedButton.icon(
style: OutlinedButton.styleFrom(
side: BorderSide(color: color, width: 1.5),
shape: const StadiumBorder(),
padding: const EdgeInsets.symmetric(horizontal: 12)),
onPressed: onPressed,
icon: Icon(icon, size: 14, color: color),
label: Text(label,
style: GoogleFonts.poppins(
fontSize: 11, fontWeight: FontWeight.bold, color: color)),
),
);
}
}