import 'dart:convert'; import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; class EditBalitaPage extends StatefulWidget { final Map data; const EditBalitaPage({super.key, required this.data}); @override State createState() => _EditBalitaPageState(); } class _EditBalitaPageState extends State { final _formKey = GlobalKey(); final namaC = TextEditingController(); final nikC = TextEditingController(); final tglLahirC = TextEditingController(); final usiaC = TextEditingController(); final tempatLahirC = TextEditingController(); final anakKeC = TextEditingController(); final beratC = TextEditingController(); final panjangC = TextEditingController(); final tglDaftarC = TextEditingController(); bool _isSaving = false; bool _isLoadingIbu = true; List ibuList = []; String? selectedIbuId; String? selectedJK; // Tambahkan Variabel Status String? selectedStatus; int usiaBulan = 0; @override void initState() { super.initState(); namaC.text = widget.data["nama"] ?? ""; nikC.text = widget.data["nik_balita"] ?? ""; tglLahirC.text = widget.data["tanggal_lahir"] ?? ""; tempatLahirC.text = widget.data["tempat_lahir"] ?? ""; anakKeC.text = widget.data["anak_ke"]?.toString() ?? ""; beratC.text = widget.data["berat_lahir"]?.toString() ?? ""; panjangC.text = widget.data["panjang_lahir"]?.toString() ?? ""; tglDaftarC.text = widget.data["tanggal_daftar"] ?? ""; selectedIbuId = widget.data["ibu_id"]?.toString(); selectedJK = widget.data["jenis_kelamin"]; // Inisialisasi Status dari data yang diterima selectedStatus = widget.data["status"]?.toString().toLowerCase(); if (tglLahirC.text.isNotEmpty) { try { DateTime tgl = DateTime.parse(tglLahirC.text); _hitungUsia(tgl); } catch (e) { usiaBulan = int.tryParse(widget.data["usia"]?.toString() ?? "0") ?? 0; _setUsiaText(); } } else { usiaBulan = int.tryParse(widget.data["usia"]?.toString() ?? "0") ?? 0; _setUsiaText(); } _loadIbu(); } @override void dispose() { namaC.dispose(); nikC.dispose(); tglLahirC.dispose(); usiaC.dispose(); tempatLahirC.dispose(); anakKeC.dispose(); beratC.dispose(); panjangC.dispose(); tglDaftarC.dispose(); super.dispose(); } Future _loadIbu() async { try { final prefs = await SharedPreferences.getInstance(); final String? role = prefs.getString("role"); 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) { List allIbu = data["data"] ?? []; if (mounted) { setState(() { if (role == 'kader' && userDusunId != "" && userDusunId != "0") { ibuList = allIbu.where((ibu) { return ibu["dusun_id"].toString() == userDusunId; }).toList(); bool exists = ibuList.any((e) => e["id"].toString() == selectedIbuId); if (!exists) { var currentIbu = allIbu.firstWhere( (e) => e["id"].toString() == selectedIbuId, orElse: () => null); if (currentIbu != null) { ibuList.add(currentIbu); } else { ibuList.add({ "id": selectedIbuId, "label": widget.data["nama_ibu"] ?? "Ibu Saat Ini" }); } } } else { ibuList = allIbu; } _isLoadingIbu = false; }); } } } catch (e) { log("Error load ibu: $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) { bulan--; final prevMonth = DateTime(now.year, now.month, 0); hari += prevMonth.day; } if (bulan < 0) { tahun--; bulan += 12; } usiaBulan = (tahun * 12) + bulan; _setUsiaText(tahun, bulan, hari); } void _setUsiaText([int? tahun, int? bulan, int? hari]) { if (tahun == null || bulan == null) { tahun = usiaBulan ~/ 12; bulan = usiaBulan % 12; hari = 0; } usiaC.text = "$tahun tahun $bulan bulan $hari hari"; } Future _pickDate(TextEditingController controller) async { DateTime initialDate = DateTime.now(); if (controller.text.isNotEmpty) { try { initialDate = DateTime.parse(controller.text); } catch (_) {} } final picked = await showDatePicker( context: context, firstDate: DateTime(2000), lastDate: DateTime.now(), initialDate: initialDate, ); if (picked != null) { setState(() { controller.text = picked.toIso8601String().split("T").first; if (controller == tglLahirC) { _hitungUsia(picked); } }); } } Future _update() async { if (!_formKey.currentState!.validate()) return; if (selectedIbuId == null || selectedJK == null || selectedStatus == null) { _showSnackBar("Lengkapi data wajib terlebih dahulu"); return; } setState(() => _isSaving = true); try { final response = await http.post( Uri.parse( "http://ta.myhost.id/E31230549/mposyandu_api/balita/edit_balita.php"), body: { "id": widget.data["id"].toString(), "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!, // Kirim status ke API }, ); log("Response: ${response.body}"); final data = json.decode(response.body); if (data["success"] == true) { if (!mounted) return; _showSnackBar("Data berhasil diupdate"); Navigator.pop(context, true); } else { _showSnackBar(data["message"] ?? "Gagal update"); } } catch (e) { log("Error update: $e"); _showSnackBar("Terjadi kesalahan koneksi"); } finally { if (mounted) setState(() => _isSaving = false); } } void _showSnackBar(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( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( "Edit Data Balita", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), const SizedBox(height: 24), _isLoadingIbu ? const Center(child: CircularProgressIndicator()) : DropdownButtonFormField( isExpanded: true, value: selectedIbuId, style: GoogleFonts.poppins( fontSize: 12, color: Colors.black), decoration: _decoration("Pilih Ibu (Orang Tua)"), items: ibuList.map((item) { return DropdownMenuItem( value: item["id"].toString(), child: Text(item["label"] ?? item["nama"] ?? "", overflow: TextOverflow.ellipsis, style: GoogleFonts.poppins(fontSize: 12)), ); }).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), DropdownButtonFormField( 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 ? "Pilih jenis kelamin" : null, ), const SizedBox(height: 16), _input("Tempat Lahir", tempatLahirC, isOptional: true), 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, color: Colors.black), ), 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, isOptional: true), _input("Berat Lahir (kg)", beratC, keyboard: const TextInputType.numberWithOptions( decimal: true), isOptional: true), _input("Panjang Lahir (cm)", panjangC, keyboard: const TextInputType.numberWithOptions( decimal: true), isOptional: true), // DROPDOWN STATUS BARU DropdownButtonFormField( 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), validator: (v) => v == null ? "Pilih status" : null, ), const SizedBox(height: 16), TextFormField( controller: tglDaftarC, readOnly: true, style: GoogleFonts.poppins(fontSize: 12), onTap: () => _pickDate(tglDaftarC), decoration: _decoration("Tanggal Daftar").copyWith( suffixIcon: const Icon(Icons.calendar_today, size: 18, color: Colors.black), ), validator: (v) => (v == null || v.isEmpty) ? "Wajib diisi" : null, ), const SizedBox(height: 28), SizedBox( height: 50, child: OutlinedButton( onPressed: _isSaving ? null : _update, style: OutlinedButton.styleFrom( side: const BorderSide( color: Colors.blueAccent, width: 2), shape: const StadiumBorder(), ), child: _isSaving ? const Center( child: SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.blueAccent))) : Text("Simpan Perubahan", style: GoogleFonts.poppins( fontWeight: FontWeight.bold, fontSize: 14, color: Colors.blueAccent)), ), ) ], ), ), ), ), ), ), ); } Widget _input(String label, TextEditingController c, {TextInputType keyboard = TextInputType.text, bool isOptional = false}) { return Padding( padding: const EdgeInsets.only(bottom: 16), child: TextFormField( controller: c, keyboardType: keyboard, style: GoogleFonts.poppins(fontSize: 12), decoration: _decoration(label), validator: (v) { if (isOptional) return null; return (v == null || v.trim().isEmpty) ? "$label wajib diisi" : 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), ); } }