MIF_E31230549/lib/kader/crud_balita/tambah_balita.dart

368 lines
13 KiB
Dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
class TambahBalitaPage extends StatefulWidget {
const TambahBalitaPage({super.key});
@override
State<TambahBalitaPage> createState() => _TambahBalitaPageState();
}
class _TambahBalitaPageState extends State<TambahBalitaPage> {
final _formKey = GlobalKey<FormState>();
final namaC = TextEditingController();
final nikC = TextEditingController();
final tglLahirC = TextEditingController();
final tempatLahirC = TextEditingController();
final anakKeC = TextEditingController();
final beratC = TextEditingController();
final panjangC = TextEditingController();
final tglDaftarC = TextEditingController();
final usiaC = TextEditingController();
bool _isSaving = false;
bool _isLoadingIbu = true;
List ibuList = [];
String? selectedIbuId;
String? selectedJK;
// Tambahkan Variabel Status
String selectedStatus = "belum lolos"; // Default sesuai DB
@override
void initState() {
super.initState();
tglDaftarC.text = DateTime.now().toIso8601String().split("T").first;
_loadIbu();
}
@override
void dispose() {
namaC.dispose();
nikC.dispose();
tglLahirC.dispose();
tempatLahirC.dispose();
anakKeC.dispose();
beratC.dispose();
panjangC.dispose();
tglDaftarC.dispose();
usiaC.dispose();
super.dispose();
}
Future<void> _loadIbu() async {
try {
final prefs = await SharedPreferences.getInstance();
final dynamic rawDusunId = prefs.get("dusun_id");
final String userDusunId = rawDusunId?.toString() ?? "";
final res = await http.get(
Uri.parse(
"http://ta.myhost.id/E31230549/mposyandu_api/ibu/get_ibu_dropdown.php?dusun_id=$userDusunId"),
);
final data = json.decode(res.body);
if (data["success"] == true) {
setState(() {
ibuList = data["data"] ?? [];
_isLoadingIbu = false;
});
} else {
if (mounted) setState(() => _isLoadingIbu = false);
}
} catch (e) {
if (mounted) setState(() => _isLoadingIbu = false);
}
}
void _hitungUsia(DateTime tgl) {
final now = DateTime.now();
int tahun = now.year - tgl.year;
int bulan = now.month - tgl.month;
int hari = now.day - tgl.day;
if (hari < 0) {
final prevMonth = DateTime(now.year, now.month, 0);
hari += prevMonth.day;
bulan--;
}
if (bulan < 0) {
bulan += 12;
tahun--;
}
usiaC.text = "$tahun tahun $bulan bulan $hari hari";
}
Future<void> _pickDate(TextEditingController controller) async {
final picked = await showDatePicker(
context: context,
firstDate: DateTime(2000),
lastDate: DateTime.now(),
initialDate: DateTime.now(),
);
if (picked != null) {
setState(() {
controller.text = picked.toIso8601String().split("T").first;
if (controller == tglLahirC) {
_hitungUsia(picked);
}
});
}
}
Future<void> _simpan() async {
if (!_formKey.currentState!.validate()) return;
if (selectedIbuId == null) {
_showMsg("Pilih ibu terlebih dahulu");
return;
}
if (selectedJK == null) {
_showMsg("Pilih jenis kelamin");
return;
}
setState(() => _isSaving = true);
try {
final url = Uri.parse(
"http://ta.myhost.id/E31230549/mposyandu_api/balita/tambah_balita.php");
final response = await http.post(url, body: {
"ibu_id": selectedIbuId!,
"nama": namaC.text.trim(),
"nik_balita": nikC.text.trim(),
"jenis_kelamin": selectedJK!,
"tanggal_lahir": tglLahirC.text.trim(),
"tempat_lahir": tempatLahirC.text.trim(),
"anak_ke": anakKeC.text.trim(),
"berat_lahir": beratC.text.trim(),
"panjang_lahir": panjangC.text.trim(),
"tanggal_daftar": tglDaftarC.text.trim(),
"status": selectedStatus, // Mengirim status ke API
});
final data = json.decode(response.body);
if (data["success"] == true) {
_showMsg("Data balita berhasil disimpan");
if (mounted) Navigator.pop(context, true);
} else {
_showMsg(data["message"] ?? "Gagal simpan");
}
} catch (e) {
_showMsg("Gagal koneksi server");
} finally {
if (mounted) setState(() => _isSaving = false);
}
}
void _showMsg(String msg) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(msg, style: GoogleFonts.poppins(fontSize: 12))),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
title: Text("",
style:
GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600)),
),
backgroundColor: const Color(0xfff4f6fb),
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 420),
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: const [
BoxShadow(
blurRadius: 16,
color: Colors.black12,
offset: Offset(0, 8))
],
),
child: Form(
key: _formKey,
child: Column(
children: [
Text("Tambah Data Balita",
style: GoogleFonts.poppins(
fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 24),
_isLoadingIbu
? const Center(child: CircularProgressIndicator())
: DropdownButtonFormField<String>(
isExpanded: true,
value: selectedIbuId,
style: GoogleFonts.poppins(
fontSize: 12, color: Colors.black),
decoration: _decoration("Pilih Ibu (Orang Tua)"),
items: ibuList.map((item) {
return DropdownMenuItem<String>(
value: item["id"].toString(),
child: Text(
"${item["nama"]} (${item["nama_suami"] ?? '-'})",
overflow: TextOverflow.ellipsis),
);
}).toList(),
onChanged: (v) => setState(() => selectedIbuId = v),
validator: (v) =>
v == null ? "Ibu wajib dipilih" : null,
),
const SizedBox(height: 16),
_input("Nama Lengkap Balita", namaC),
_input("NIK Balita", nikC,
keyboard: TextInputType.number, isNik: true),
DropdownButtonFormField<String>(
value: selectedJK,
style: GoogleFonts.poppins(
fontSize: 12, color: Colors.black),
decoration: _decoration("Jenis Kelamin"),
items: const [
DropdownMenuItem(value: "L", child: Text("Laki-laki")),
DropdownMenuItem(value: "P", child: Text("Perempuan")),
],
onChanged: (v) => setState(() => selectedJK = v),
validator: (v) => v == null ? "Wajib dipilih" : null,
),
const SizedBox(height: 16),
_input("Tempat Lahir", tempatLahirC),
TextFormField(
controller: tglLahirC,
readOnly: true,
style: GoogleFonts.poppins(fontSize: 12),
onTap: () => _pickDate(tglLahirC),
decoration: _decoration("Tanggal Lahir").copyWith(
suffixIcon: const Icon(Icons.calendar_today, size: 18),
),
validator: (v) =>
v == null || v.isEmpty ? "Wajib diisi" : null,
),
const SizedBox(height: 16),
TextFormField(
controller: usiaC,
readOnly: true,
style: GoogleFonts.poppins(fontSize: 12),
decoration: _decoration("Usia (Otomatis)"),
),
const SizedBox(height: 16),
_input("Anak Ke-", anakKeC, keyboard: TextInputType.number),
_input("Berat Lahir (kg)", beratC,
keyboard: TextInputType.number),
_input("Panjang Lahir (cm)", panjangC,
keyboard: TextInputType.number),
// DROPDOWN STATUS BARU
DropdownButtonFormField<String>(
value: selectedStatus,
style: GoogleFonts.poppins(
fontSize: 12, color: Colors.black),
decoration: _decoration("Status Seleksi"),
items: const [
DropdownMenuItem(
value: "belum lolos", child: Text("Belum Lolos")),
DropdownMenuItem(value: "lolos", child: Text("Lolos")),
],
onChanged: (v) => setState(() => selectedStatus = v!),
),
const SizedBox(height: 16),
TextFormField(
controller: tglDaftarC,
readOnly: true,
style: GoogleFonts.poppins(fontSize: 12),
onTap: () => _pickDate(tglDaftarC),
decoration: _decoration("Tanggal Pendaftaran").copyWith(
suffixIcon: const Icon(Icons.calendar_today, size: 18),
),
),
const SizedBox(height: 28),
SizedBox(
width: double.infinity,
height: 50,
child: OutlinedButton(
onPressed: _isSaving ? null : _simpan,
style: OutlinedButton.styleFrom(
side: const BorderSide(
color: Colors.blueAccent, width: 1.5),
shape: const StadiumBorder(),
),
child: _isSaving
? const SizedBox(
height: 20,
width: 20,
child:
CircularProgressIndicator(strokeWidth: 2))
: Text("Simpan Data Balita",
style: GoogleFonts.poppins(
fontWeight: FontWeight.bold,
color: Colors.blueAccent)),
),
),
],
),
),
),
),
),
),
);
}
Widget _input(String label, TextEditingController c,
{TextInputType keyboard = TextInputType.text, bool isNik = false}) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: TextFormField(
controller: c,
keyboardType: keyboard,
inputFormatters: isNik
? [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(16)
]
: null,
style: GoogleFonts.poppins(fontSize: 12),
decoration: _decoration(label),
validator: (v) {
if (![
"Tempat Lahir",
"Anak Ke-",
"Berat Lahir (kg)",
"Panjang Lahir (cm)"
].contains(label)) {
if (v == null || v.isEmpty) return "$label wajib";
}
if (isNik && v != null && v.isNotEmpty && v.length != 16)
return "Harus 16 digit";
return null;
},
),
);
}
InputDecoration _decoration(String label) {
return InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: label,
labelStyle: GoogleFonts.poppins(fontSize: 12),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
);
}
}