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 EditEdukasiBalitaPage extends StatefulWidget { final Map data; const EditEdukasiBalitaPage({super.key, required this.data}); @override State createState() => _EditEdukasiBalitaPageState(); } class _EditEdukasiBalitaPageState extends State { final _formKey = GlobalKey(); late TextEditingController _judulController; late TextEditingController _deskripsiController; bool isSubmitting = false; File? _selectedImage; Uint8List? _webImage; final picker = ImagePicker(); // Sesuaikan URL jika sudah beralih ke hosting ta.myhost.id final String urlEdit = "http://ta.myhost.id/E31230549/mposyandu_api/edukasi_balita/edit_edukasi_balita.php"; @override void initState() { super.initState(); _judulController = TextEditingController(text: widget.data['judul']); // Memproses deskripsi agar kode JSON Delta dikonversi menjadi teks biasa String rawDeskripsi = widget.data['deskripsi'] ?? ""; _deskripsiController = TextEditingController( text: _convertJsonToPlainText(rawDeskripsi), ); } // Fungsi untuk membersihkan format JSON Quill menjadi Plain Text String _convertJsonToPlainText(String input) { try { // Jika input diawali dengan '[' berarti itu format JSON Delta 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: Deskripsi bukan format JSON, menggunakan teks asli."); } return input; // Kembalikan teks asli jika bukan JSON atau gagal decode } @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("Terjadi kesalahan: $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( "Perbarui Edukasi Balita", style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 10), const Divider(), const SizedBox(height: 20), _buildLabel("Gambar Edukasi"), _buildImagePreview(), const SizedBox(height: 30), _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], contentPadding: const EdgeInsets.all(15), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: Colors.grey.shade400), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Colors.blue), ), ), validator: (value) => value == null || value.isEmpty ? "Wajib diisi" : null, ); } Widget _buildImagePreview() { 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 ? Image.file(_selectedImage!, fit: BoxFit.cover) : _webImage != null ? Image.memory(_webImage!, 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.image, size: 50, color: Colors.grey), ) : const Icon(Icons.image, size: 50, color: Colors.grey)), ), ), const SizedBox(height: 12), SizedBox( height: 35, child: OutlinedButton.icon( onPressed: pickImage, icon: const Icon(Icons.image, size: 16), label: Text( "Ganti Gambar", style: GoogleFonts.poppins(fontSize: 12), ), style: OutlinedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), foregroundColor: Colors.blue, side: BorderSide(color: Colors.grey.shade300), ), ), ), ], ), ); } Widget _buildLabel(String label) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Text( label, style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ); } Widget _buildTitleField() { return TextFormField( controller: _judulController, style: GoogleFonts.poppins(fontSize: 14), decoration: InputDecoration( hintText: "Masukkan judul", filled: true, fillColor: Colors.grey[50], contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 12), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: Colors.grey.shade400), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Colors.blue), ), ), validator: (value) => value == null || value.isEmpty ? "Wajib diisi" : null, ); } Widget _buildSubmitButton() { return Align( alignment: Alignment.centerRight, child: SizedBox( width: 180, child: ElevatedButton( onPressed: isSubmitting ? null : _updateData, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), child: isSubmitting ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2), ) : Text("Simpan Perubahan", style: GoogleFonts.poppins(fontWeight: FontWeight.bold)), ), ), ); } }