MIF_E31230549/lib/kader/crud_ibu/edit_ibu.dart

409 lines
14 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 EditIbuPage extends StatefulWidget {
final Map<String, dynamic> data;
const EditIbuPage({super.key, required this.data});
@override
State<EditIbuPage> createState() => _EditIbuPageState();
}
class _EditIbuPageState extends State<EditIbuPage> {
final _formKey = GlobalKey<FormState>();
// ================= CONTROLLER =================
final nikC = TextEditingController();
final noKkC = TextEditingController();
final namaC = TextEditingController();
final namaSuamiC = TextEditingController();
final tempatLahirC = TextEditingController();
final tglC = TextEditingController();
final pendidikanC = TextEditingController();
final pekerjaanC = TextEditingController();
final alamatC = TextEditingController();
final hpC = TextEditingController();
final emailC = TextEditingController();
final desaC = TextEditingController();
final dusunC = TextEditingController();
String? selectedGolDarah;
String? selectedAgama;
int? selectedDesa;
int? selectedDusun;
bool _isSaving = false;
bool isKader = false;
String? _emailError;
final List<String> golDarahList = const ['A', 'B', 'AB', 'O', '-'];
final List<String> agamaList = const [
'Islam',
'Kristen',
'Katolik',
'Hindu',
'Buddha',
'Konghucu'
];
@override
void initState() {
super.initState();
nikC.text = widget.data["nik"]?.toString() ?? "";
noKkC.text = widget.data["no_kk"]?.toString() ?? "";
namaC.text = widget.data["nama"]?.toString() ?? "";
namaSuamiC.text = widget.data["nama_suami"]?.toString() ?? "";
tempatLahirC.text = widget.data["tempat_lahir"]?.toString() ?? "";
tglC.text = widget.data["tanggal_lahir"]?.toString() ?? "";
pendidikanC.text = widget.data["pendidikan"]?.toString() ?? "";
pekerjaanC.text = widget.data["pekerjaan"]?.toString() ?? "";
alamatC.text = widget.data["alamat_detail"]?.toString() ?? "";
hpC.text = widget.data["no_hp"]?.toString() ?? "";
emailC.text = widget.data["email"]?.toString() ?? "";
selectedGolDarah = widget.data["golongan_darah"];
selectedAgama = widget.data["agama"];
selectedDesa = int.tryParse(widget.data["desa_id"].toString());
selectedDusun = int.tryParse(widget.data["dusun_id"].toString());
_checkUserRole();
}
@override
void dispose() {
nikC.dispose();
noKkC.dispose();
namaC.dispose();
namaSuamiC.dispose();
tempatLahirC.dispose();
tglC.dispose();
pendidikanC.dispose();
pekerjaanC.dispose();
alamatC.dispose();
hpC.dispose();
emailC.dispose();
desaC.dispose();
dusunC.dispose();
super.dispose();
}
Future<void> _checkUserRole() async {
final prefs = await SharedPreferences.getInstance();
final role = prefs.getString('role');
if (role == 'kader') setState(() => isKader = true);
_getNamaWilayah();
}
Future<void> _getNamaWilayah() async {
try {
final resDesa = await http
.get(Uri.parse("http://ta.myhost.id/E31230549/mposyandu_api/desa/get_desa.php"));
final dataDesa = _safeJson(resDesa.body);
if (dataDesa != null) {
final list = dataDesa is List ? dataDesa : dataDesa['data'];
final d = list.firstWhere(
(e) => int.parse(e['id'].toString()) == selectedDesa,
orElse: () => null);
if (d != null) desaC.text = d['nama_desa'].toString();
}
if (selectedDesa != null) {
final resDusun = await http.get(Uri.parse(
"http://ta.myhost.id/E31230549/mposyandu_api/dusun/get_dusun.php?desa_id=$selectedDesa"));
final dataDusun = _safeJson(resDusun.body);
if (dataDusun != null) {
final list = dataDusun is List ? dataDusun : dataDusun['data'];
final du = list.firstWhere(
(e) => int.parse(e['id'].toString()) == selectedDusun,
orElse: () => null);
if (du != null) dusunC.text = du['nama_dusun'].toString();
}
}
} catch (e) {
debugPrint("Gagal memuat wilayah: $e");
}
}
dynamic _safeJson(String body) {
try {
if (body.trim().startsWith("<")) return null;
return json.decode(body);
} catch (e) {
return null;
}
}
Future<void> _update() async {
setState(() => _emailError = null);
if (!_formKey.currentState!.validate()) return;
setState(() => _isSaving = true);
final Map<String, String> bodyData = {
"id": widget.data["id"].toString(),
"nik": nikC.text.trim(),
"no_kk": noKkC.text.trim(),
"nama": namaC.text.trim(),
"nama_suami": namaSuamiC.text.trim(),
"tempat_lahir": tempatLahirC.text.trim(),
"tanggal_lahir": tglC.text.trim(),
"golongan_darah": selectedGolDarah ?? "-",
"pendidikan": pendidikanC.text.trim(),
"pekerjaan": pekerjaanC.text.trim(),
"agama": selectedAgama ?? "",
"no_hp": hpC.text.trim(),
"email": emailC.text.trim(),
"desa_id": selectedDesa.toString(),
"dusun_id": selectedDusun.toString(),
"alamat_detail": alamatC.text.trim(),
};
try {
final res = await http.post(
Uri.parse("http://ta.myhost.id/E31230549/mposyandu_api/ibu/update_ibu.php"),
body: bodyData,
);
final responseData = _safeJson(res.body);
if (responseData != null) {
if (responseData["success"] == true) {
if (!mounted) return;
_showMsg("Data berhasil diperbarui");
Navigator.pop(context, true);
} else {
String serverMsg = responseData["message"] ?? "Gagal memperbarui";
if (serverMsg.toLowerCase().contains("email")) {
setState(() => _emailError = "Email sudah terdaftar");
} else {
_showMsg("Gagal: $serverMsg");
}
}
} else {
_showMsg("Terjadi kesalahan pada server (Format Response Salah)");
}
} catch (e) {
_showMsg("Error Koneksi: $e");
} finally {
if (mounted) setState(() => _isSaving = false);
}
}
void _showMsg(String msg) {
if (!mounted) return;
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,
elevation: 0,
title: Text("",
style:
GoogleFonts.poppins(fontSize: 18, fontWeight: FontWeight.w600)),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 950),
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: const [
BoxShadow(blurRadius: 10, color: Colors.black12)
]),
child: Form(
key: _formKey,
child: Column(
children: [
// ================= JUDUL DI DALAM CARD =================
Padding(
padding: const EdgeInsets.only(bottom: 30),
child: Text(
"Edit Data Ibu",
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
// ========================================================
Wrap(
spacing: 20,
runSpacing: 20,
alignment: WrapAlignment.center,
children: [
_input("NIK", nikC, isNikOrKk: true),
_input("No KK", noKkC, isNikOrKk: true),
_input("Nama Ibu", namaC),
_input("Nama Suami", namaSuamiC),
_input("Tempat Lahir", tempatLahirC),
_dateInput(),
_dropdown("Gol. Darah", selectedGolDarah, golDarahList,
(v) => setState(() => selectedGolDarah = v)),
_dropdown("Agama", selectedAgama, agamaList,
(v) => setState(() => selectedAgama = v)),
_input("Pendidikan", pendidikanC),
_input("Pekerjaan", pekerjaanC),
_input("No HP", hpC, isPhone: true),
_input("Email", emailC, isEmail: true),
_input("Desa", desaC, readOnly: true),
_input("Dusun", dusunC, readOnly: true),
_input("Alamat Detail", alamatC, lines: 2),
],
),
const SizedBox(height: 40),
SizedBox(
width: 300, // Ukuran tombol disesuaikan agar rapi
height: 50,
child: OutlinedButton(
onPressed: _isSaving ? null : _update,
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.blue, width: 2),
shape: const StadiumBorder(),
),
child: _isSaving
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
color: Colors.blue, strokeWidth: 2))
: Text("Simpan Perubahan",
style: GoogleFonts.poppins(
color: Colors.blue,
fontSize: 14,
fontWeight: FontWeight.bold,
)),
),
)
],
),
),
),
),
),
),
);
}
// Widget Helper _input, _dateInput, _dropdown tetap sama seperti sebelumnya...
Widget _input(String label, TextEditingController c,
{bool isNikOrKk = false,
bool isPhone = false,
bool isEmail = false,
bool readOnly = false,
int lines = 1}) {
return SizedBox(
width: 280,
child: TextFormField(
controller: c,
readOnly: readOnly,
onChanged: (v) {
if (isEmail && _emailError != null) {
setState(() => _emailError = null);
}
},
keyboardType: (isNikOrKk || isPhone)
? TextInputType.number
: (isEmail ? TextInputType.emailAddress : TextInputType.text),
maxLines: lines,
inputFormatters: [
if (isNikOrKk || isPhone) FilteringTextInputFormatter.digitsOnly,
if (isNikOrKk) LengthLimitingTextInputFormatter(16),
if (isPhone) LengthLimitingTextInputFormatter(13),
],
style: GoogleFonts.poppins(fontSize: 12),
decoration: InputDecoration(
labelText: label,
filled: readOnly,
fillColor: readOnly ? Colors.grey[100] : Colors.white,
errorText: isEmail ? _emailError : null,
labelStyle: GoogleFonts.poppins(fontSize: 12),
errorStyle: GoogleFonts.poppins(color: Colors.red, fontSize: 10),
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(10))),
validator: (v) {
if (v == null || v.isEmpty) return "Wajib diisi";
if (isNikOrKk && v.length != 16) return "Harus 16 digit angka";
if (isPhone && (v.length < 10 || v.length > 13))
return "Harus 10 - 13 digit";
if (isEmail) {
final emailRegExp = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegExp.hasMatch(v)) return "Format email tidak valid";
}
return null;
},
),
);
}
Widget _dateInput() {
return SizedBox(
width: 280,
child: TextFormField(
controller: tglC,
readOnly: true,
style: GoogleFonts.poppins(fontSize: 12),
decoration: InputDecoration(
labelText: "Tanggal Lahir",
labelStyle: GoogleFonts.poppins(fontSize: 12),
errorStyle: GoogleFonts.poppins(color: Colors.red, fontSize: 10),
suffixIcon: const Icon(Icons.calendar_today, size: 18),
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(10))),
onTap: () async {
DateTime initial =
DateTime.tryParse(tglC.text) ?? DateTime(1990, 1, 1);
DateTime? p = await showDatePicker(
context: context,
initialDate: initial,
firstDate: DateTime(1950),
lastDate: DateTime.now());
if (p != null) {
setState(() => tglC.text = p.toIso8601String().split("T").first);
}
},
validator: (v) => (v == null || v.isEmpty) ? "Wajib diisi" : null,
),
);
}
Widget _dropdown(
String label, String? val, List<String> items, Function(String?) onChg) {
return SizedBox(
width: 280,
child: DropdownButtonFormField<String>(
value: val,
style: GoogleFonts.poppins(color: Colors.black, fontSize: 12),
items: items
.map((e) => DropdownMenuItem(
value: e,
child: Text(e, style: GoogleFonts.poppins(fontSize: 12))))
.toList(),
onChanged: onChg,
decoration: InputDecoration(
labelText: label,
labelStyle: GoogleFonts.poppins(fontSize: 12),
errorStyle: GoogleFonts.poppins(color: Colors.red, fontSize: 10),
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(10))),
validator: (v) => (v == null || v.isEmpty) ? "Wajib dipilih" : null,
),
);
}
}