456 lines
16 KiB
Dart
456 lines
16 KiB
Dart
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<String, dynamic> data;
|
|
|
|
const EditBalitaPage({super.key, required this.data});
|
|
|
|
@override
|
|
State<EditBalitaPage> createState() => _EditBalitaPageState();
|
|
}
|
|
|
|
class _EditBalitaPageState extends State<EditBalitaPage> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
|
|
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<void> _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<void> _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<void> _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<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["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<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 ? "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<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),
|
|
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),
|
|
);
|
|
}
|
|
}
|