MIF_E31230549/lib/kader/crud_ibu_hamil/tambah_ibu_hamil.dart

382 lines
14 KiB
Dart

import 'dart:convert';
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 TambahIbuHamilPage extends StatefulWidget {
const TambahIbuHamilPage({super.key});
@override
State<TambahIbuHamilPage> createState() => _TambahIbuHamilPageState();
}
class _TambahIbuHamilPageState extends State<TambahIbuHamilPage> {
final _formKey = GlobalKey<FormState>();
String? selectedIbuId;
List<dynamic> listIbu = [];
final hphtC = TextEditingController();
final usiaC = TextEditingController();
final hplC = TextEditingController();
final tglPersalinanSblmC = TextEditingController();
final gravidaC = TextEditingController();
final paraC = TextEditingController();
final abortusC = TextEditingController();
final hidupC = TextEditingController();
// Dropdown Values
String selectedStatus = "aktif";
final List<String> listStatus = ['aktif', 'keguguran', 'melahirkan'];
// Diubah menjadi null agar memicu tampilan Hint
String? selectedPembiayaan;
final List<String> listPembiayaan = [
'JKN',
'JAMPERSAL',
'ASURANSI KESEHATAN LAIN',
'MANDIRI'
];
bool _isSaving = false;
bool _isLoadingIbu = true;
@override
void initState() {
super.initState();
_fetchIbu();
}
@override
void dispose() {
hphtC.dispose();
usiaC.dispose();
hplC.dispose();
tglPersalinanSblmC.dispose();
gravidaC.dispose();
paraC.dispose();
abortusC.dispose();
hidupC.dispose();
super.dispose();
}
void _hitungDariHPHT(DateTime hphtDate) {
final now = DateTime.now();
final diffDays = now.difference(hphtDate).inDays;
final minggu = diffDays < 0 ? 0 : (diffDays / 7).floor();
usiaC.text = minggu.toString();
final hplDate = hphtDate.add(const Duration(days: 280));
hplC.text = hplDate.toIso8601String().split("T").first;
}
Future<void> _fetchIbu() async {
try {
final prefs = await SharedPreferences.getInstance();
final dynamic rawDusunId = prefs.get("dusun_id");
final String userDusunId = rawDusunId?.toString() ?? "";
final url = Uri.parse(
"http://ta.myhost.id/E31230549/mposyandu_api/ibu/get_ibu.php?dusun_id=$userDusunId");
final response = await http.get(url);
final data = json.decode(response.body);
if (data["success"] == true) {
setState(() {
listIbu = data["data"] ?? [];
_isLoadingIbu = false;
});
} else {
if (mounted) setState(() => _isLoadingIbu = false);
}
} catch (e) {
if (mounted) setState(() => _isLoadingIbu = false);
}
}
Future<void> _simpan() async {
if (!_formKey.currentState!.validate()) return;
if (selectedIbuId == null) {
_showSnackBar("Ibu wajib dipilih");
return;
}
setState(() => _isSaving = true);
try {
final url = Uri.parse(
"http://ta.myhost.id/E31230549/mposyandu_api/ibu_hamil/tambah_ibu_hamil.php");
// Data dikirim dengan pengaman ?? "" agar jika kosong tetap terkirim sebagai string kosong
final response = await http.post(url, body: {
"ibu_id": selectedIbuId!,
"hpht": hphtC.text.trim(),
"hpl": hplC.text.trim(),
"tanggal_persalinan_sebelumnya": tglPersalinanSblmC.text.trim(),
"gravida": gravidaC.text.trim(),
"para": paraC.text.trim(),
"abortus": abortusC.text.trim(),
"hidup": hidupC.text.trim(),
"status": selectedStatus,
"pembiayaan": selectedPembiayaan ?? "",
});
final data = json.decode(response.body);
if (data["success"] == true) {
_showSnackBar("Data berhasil disimpan");
if (mounted) Navigator.pop(context, true);
} else {
_showSnackBar(data["message"] ?? "Gagal menyimpan");
}
} catch (e) {
_showSnackBar("Gagal: $e");
} finally {
if (mounted) setState(() => _isSaving = false);
}
}
void _showSnackBar(String msg) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(msg, style: GoogleFonts.poppins(fontSize: 12))),
);
}
Future<void> _pickHPHT() async {
final picked = await showDatePicker(
context: context,
firstDate: DateTime(2000),
lastDate: DateTime.now(),
initialDate: DateTime.now(),
);
if (picked != null) {
hphtC.text = picked.toIso8601String().split("T").first;
_hitungDariHPHT(picked);
}
}
Future<void> _pickTanggalPersalinan() async {
final picked = await showDatePicker(
context: context,
firstDate: DateTime(1990),
lastDate: DateTime.now(),
initialDate: DateTime.now(),
);
if (picked != null) {
tglPersalinanSblmC.text = picked.toIso8601String().split("T").first;
}
}
@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.start,
children: [
Center(
child: Text(
"Tambah Data Ibu Hamil",
style: GoogleFonts.poppins(
fontSize: 18, fontWeight: FontWeight.w700),
),
),
const SizedBox(height: 24),
_isLoadingIbu
? const Center(child: CircularProgressIndicator())
: DropdownButtonFormField<String>(
isExpanded: true,
value: selectedIbuId,
hint: Text("Pilih Ibu",
style: GoogleFonts.poppins(fontSize: 12)),
style: GoogleFonts.poppins(
fontSize: 12, color: Colors.black),
decoration: _decoration("Pilih Ibu"),
items:
listIbu.map<DropdownMenuItem<String>>((item) {
return DropdownMenuItem<String>(
value: item["id"].toString(),
child: Text(
"${item["nama"]} (${item["nama_suami"] ?? '_'})",
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),
TextFormField(
controller: hphtC,
readOnly: true,
onTap: _pickHPHT,
style: GoogleFonts.poppins(fontSize: 12),
decoration: _decoration("HPHT").copyWith(
suffixIcon: const Icon(Icons.calendar_today,
size: 18, color: Colors.black),
),
validator: (v) => v!.isEmpty ? "HPHT wajib diisi" : null,
),
const SizedBox(height: 16),
TextFormField(
controller: usiaC,
readOnly: true,
style: GoogleFonts.poppins(fontSize: 12),
decoration: _decoration("Usia Kehamilan (Minggu)"),
),
const SizedBox(height: 16),
TextFormField(
controller: hplC,
readOnly: true,
style: GoogleFonts.poppins(fontSize: 12),
decoration: _decoration("HPL (Perkiraan Lahir)"),
),
const SizedBox(height: 16),
// Tanggal Persalinan Sebelumnya (Opsional)
TextFormField(
controller: tglPersalinanSblmC,
readOnly: true,
onTap: _pickTanggalPersalinan,
style: GoogleFonts.poppins(fontSize: 12),
decoration: _decoration(
"Tanggal Persalinan Sebelumnya (Opsional)")
.copyWith(
suffixIcon: const Icon(Icons.calendar_today,
size: 18, color: Colors.black),
),
),
const SizedBox(height: 16),
_input("Gravida (G)", gravidaC,
keyboard: TextInputType.number),
const SizedBox(height: 16),
_input("Para (P)", paraC, keyboard: TextInputType.number),
const SizedBox(height: 16),
_input("Abortus (A)", abortusC,
keyboard: TextInputType.number),
const SizedBox(height: 16),
_input("Hidup", hidupC, keyboard: TextInputType.number),
const SizedBox(height: 16),
// DROPDOWN PEMBIAYAAN (Opsional)
DropdownButtonFormField<String>(
isExpanded: true,
value: selectedPembiayaan,
hint: Text("Pilih Pembiayaan (Opsional)",
style: GoogleFonts.poppins(fontSize: 12)),
decoration: _decoration("Pembiayaan"),
style: GoogleFonts.poppins(
fontSize: 12, color: Colors.black),
items: listPembiayaan.map((val) {
return DropdownMenuItem(
value: val,
child: Text(val,
style: GoogleFonts.poppins(fontSize: 12)),
);
}).toList(),
onChanged: (v) => setState(() => selectedPembiayaan = v),
// Validator dihapus agar boleh kosong
),
const SizedBox(height: 16),
// DROPDOWN STATUS
DropdownButtonFormField<String>(
value: selectedStatus,
decoration: _decoration("Status"),
style: GoogleFonts.poppins(
fontSize: 12, color: Colors.black),
items: listStatus.map((val) {
return DropdownMenuItem(
value: val,
child: Text(val.toUpperCase(),
style: GoogleFonts.poppins(fontSize: 12)),
);
}).toList(),
onChanged: (v) => setState(() => selectedStatus = v!),
),
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: 2),
shape: const StadiumBorder(),
),
child: _isSaving
? const SizedBox(
height: 20,
width: 20,
child:
CircularProgressIndicator(strokeWidth: 2))
: Text("Simpan Data Ibu Hamil",
style: GoogleFonts.poppins(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Colors.blueAccent)),
),
)
],
),
),
),
),
),
),
);
}
Widget _input(String label, TextEditingController c,
{TextInputType keyboard = TextInputType.text}) {
return TextFormField(
controller: c,
keyboardType: keyboard,
style: GoogleFonts.poppins(fontSize: 12),
decoration: _decoration(label),
validator: (v) => v!.isEmpty ? "$label wajib diisi" : null,
);
}
InputDecoration _decoration(String label) {
return InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: label,
labelStyle: GoogleFonts.poppins(fontSize: 12),
errorStyle: GoogleFonts.poppins(fontSize: 10),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
);
}
}