MIF_E31230549/lib/kader/data_pemeriksaan.dart

650 lines
30 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 '../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<DataPemeriksaanBalitaPage> createState() =>
_DataPemeriksaanBalitaPageState();
}
class _DataPemeriksaanBalitaPageState extends State<DataPemeriksaanBalitaPage> {
List<Map<String, dynamic>> _dataBalita = [];
List<Map<String, dynamic>> _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<String> 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<void> _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<void> _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<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["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<Map<String, dynamic>> 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<String, dynamic> 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(),
);
}
}