import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:image_picker/image_picker.dart'; class EditEdukasiBumilPage extends StatefulWidget { final Map data; const EditEdukasiBumilPage({super.key, required this.data}); @override State createState() => _EditEdukasiBumilPageState(); } class _EditEdukasiBumilPageState extends State { final _formKey = GlobalKey(); late TextEditingController _judulController; late TextEditingController _deskripsiController; File? selectedImage; Uint8List? webImage; bool isSubmitting = false; final picker = ImagePicker(); // Jika nanti sudah migrasi ke hosting, ganti localhost menjadi ta.myhost.id final String urlEdit = "http://ta.myhost.id/E31230549/mposyandu_api/edukasi_ibu_hamil/edit_edukasi_ibu_hamil.php"; @override void initState() { super.initState(); _judulController = TextEditingController(text: widget.data['judul']); // Mengambil deskripsi dan membersihkannya dari format JSON Delta String rawDeskripsi = widget.data['deskripsi'] ?? ""; _deskripsiController = TextEditingController( text: _convertJsonToPlainText(rawDeskripsi), ); } // Fungsi pembantu untuk mengonversi format JSON Quill ke teks biasa String _convertJsonToPlainText(String input) { try { if (input.trim().startsWith('[')) { List jsonDelta = jsonDecode(input); String plainText = ""; for (var node in jsonDelta) { if (node['insert'] != null) { plainText += node['insert']; } } return plainText; } } catch (e) { debugPrint("Info: Menggunakan teks asli karena bukan format JSON."); } return input; } @override void dispose() { _judulController.dispose(); _deskripsiController.dispose(); super.dispose(); } Future pickImage() async { final picked = await picker.pickImage(source: ImageSource.gallery, imageQuality: 80); if (picked == null) return; if (kIsWeb) { webImage = await picked.readAsBytes(); } else { selectedImage = File(picked.path); } setState(() {}); } Future _updateData() async { if (!_formKey.currentState!.validate()) return; setState(() => isSubmitting = true); try { var request = http.MultipartRequest("POST", Uri.parse(urlEdit)); request.fields["id"] = widget.data['id'].toString(); request.fields["judul"] = _judulController.text; request.fields["deskripsi"] = _deskripsiController.text; if (selectedImage != null) { request.files.add( await http.MultipartFile.fromPath("gambar", selectedImage!.path)); } else if (webImage != null) { request.files.add(http.MultipartFile.fromBytes("gambar", webImage!, filename: "upload.jpg")); } var response = await request.send(); var res = await http.Response.fromStream(response); var data = jsonDecode(res.body); if (data["status"] == "success") { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Data berhasil diperbarui")), ); Navigator.pop(context, true); } else { throw data["message"] ?? "Gagal memperbarui data"; } } catch (e) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Error: $e")), ); } finally { if (mounted) setState(() => isSubmitting = false); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5F5F5), appBar: AppBar( title: Text("", style: GoogleFonts.poppins(color: Colors.white, fontSize: 16)), backgroundColor: Colors.blue, elevation: 0, centerTitle: true, iconTheme: const IconThemeData(color: Colors.white), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Center( child: Container( constraints: const BoxConstraints(maxWidth: 900), child: Card( color: Colors.white, elevation: 3, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), child: Padding( padding: const EdgeInsets.all(25), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Text( "Edit Edukasi Ibu Hamil", style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 10), const Divider(), const SizedBox(height: 20), _buildLabel("Gambar Edukasi"), _buildImageSection(), const SizedBox(height: 25), _buildLabel("Judul Edukasi"), _buildTitleField(), const SizedBox(height: 25), _buildLabel("Deskripsi"), _buildDescriptionField(), const SizedBox(height: 35), _buildSubmitButton(), ], ), ), ), ), ), ), ), ); } Widget _buildDescriptionField() { return TextFormField( controller: _deskripsiController, maxLines: 12, keyboardType: TextInputType.multiline, style: GoogleFonts.poppins(fontSize: 14), decoration: InputDecoration( hintText: "Tulis isi materi di sini...", filled: true, fillColor: Colors.grey[50], enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: Colors.grey.shade400), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Colors.blue), ), contentPadding: const EdgeInsets.all(15), ), validator: (value) => value == null || value.isEmpty ? "Wajib diisi" : null, ); } Widget _buildImageSection() { return Center( child: Column( children: [ Container( height: 200, width: 350, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), border: Border.all(color: Colors.grey.shade200), ), child: ClipRRect( borderRadius: BorderRadius.circular(10), child: selectedImage != null || webImage != null ? (kIsWeb ? Image.memory(webImage!, fit: BoxFit.cover) : Image.file(selectedImage!, fit: BoxFit.cover)) : (widget.data["gambar"] != null ? Image.network( "http://ta.myhost.id/E31230549/mposyandu_api/upload/edukasi/${widget.data['gambar']}", fit: BoxFit.cover, errorBuilder: (c, e, s) => const Icon( Icons.broken_image, size: 50, color: Colors.grey), ) : const Icon(Icons.image, size: 50, color: Colors.grey)), ), ), const SizedBox(height: 10), TextButton.icon( onPressed: pickImage, icon: const Icon(Icons.camera_alt), label: Text("Ganti Gambar", style: GoogleFonts.poppins())), ], ), ); } Widget _buildTitleField() { return TextFormField( controller: _judulController, style: GoogleFonts.poppins(fontSize: 14), decoration: InputDecoration( hintText: "Masukkan Judul", filled: true, fillColor: Colors.grey[50], enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: Colors.grey.shade400), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Colors.blue), ), contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 12), ), validator: (value) => value == null || value.isEmpty ? "Wajib diisi" : null, ); } Widget _buildSubmitButton() { return Align( alignment: Alignment.centerRight, child: SizedBox( width: 200, height: 50, child: ElevatedButton( onPressed: isSubmitting ? null : _updateData, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, foregroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), elevation: 2, ), child: isSubmitting ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2)) : Text( "Simpan Perubahan", style: GoogleFonts.poppins(fontWeight: FontWeight.bold), ), ), ), ); } Widget _buildLabel(String text) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Text(text, style: GoogleFonts.poppins( fontWeight: FontWeight.bold, fontSize: 13, color: Colors.black87)), ); } }