diff --git a/frontend/lib/admin/edit_rule_page.dart b/frontend/lib/admin/edit_rule_page.dart new file mode 100644 index 0000000..7678974 --- /dev/null +++ b/frontend/lib/admin/edit_rule_page.dart @@ -0,0 +1,438 @@ +import 'package:flutter/material.dart'; +import 'package:frontend/api_services/api_services.dart'; +import 'package:http/http.dart' as http; + +class EditRulePage extends StatefulWidget { + @override + _EditRulePageState createState() => _EditRulePageState(); + + final bool isEditing; + final bool isEditingHama; + final List selectedRuleIds; + final List selectedGejalaIds; + final List nilaiPakarList; + final int? selectedHamaId; + final int? selectedPenyakitId; + + const EditRulePage({ + Key? key, + required this.isEditing, + required this.isEditingHama, + required this.selectedRuleIds, + required this.selectedGejalaIds, + required this.nilaiPakarList, + this.selectedHamaId, + this.selectedPenyakitId, + }) : super(key: key); +} + +class _EditRulePageState extends State { + int? selectedHamaId; + int? selectedPenyakitId; + List selectedGejalaIds = [null]; + List nilaiPakarList = [0.5]; + List selectedRuleIds = []; + + bool isEditing = true; // atau false jika sedang edit penyakit + + bool isLoading = true; + + final api = ApiService(); + + // Deklarasi variabel untuk menampung data dari API + List> hamaList = []; + List> penyakitList = []; + List> gejalaList = []; + + void loadRulesForEditing() async { + try { + final fetchedRules = + isEditing ? await api.getRulesHama() : await api.getRulesPenyakit(); + + print('Fetched Rules: $fetchedRules'); + + // Filter data yang valid dan konversi dengan aman + final validRules = + fetchedRules.where((rule) { + if (rule is Map) { + // Pastikan semua key yang diperlukan ada dan nilainya tidak null + return rule.containsKey('id') && + rule.containsKey('id_gejala') && + rule.containsKey('nilai_pakar') && + (rule.containsKey('id_penyakit') || + rule.containsKey('id_hama')) && + rule['id'] != null && + rule['id_gejala'] != null && + rule['nilai_pakar'] != null && + (rule['id_penyakit'] != null || rule['id_hama'] != null); + } + return false; + }).toList(); + + // Pastikan konversi tipe data dilakukan dengan aman + setState(() { + selectedRuleIds = + validRules.map((rule) { + // Pastikan id bisa dikonversi ke int + final id = rule['id']; + return id is int ? id : (id is String ? int.tryParse(id) : null); + }).toList(); + + selectedGejalaIds = + validRules.map((rule) { + // Pastikan id_gejala bisa dikonversi ke int + final idGejala = rule['id_gejala']; + return idGejala is int + ? idGejala + : (idGejala is String ? int.tryParse(idGejala) : null); + }).toList(); + + nilaiPakarList = + validRules.map((rule) { + // Pastikan nilai_pakar bisa dikonversi ke double + final nilaiPakar = rule['nilai_pakar']; + if (nilaiPakar is double) return nilaiPakar; + if (nilaiPakar is int) return nilaiPakar.toDouble(); + if (nilaiPakar is String) + return double.tryParse(nilaiPakar) ?? 0.5; + return 0.5; // Nilai default + }).toList(); + + print('Valid Rules: $validRules'); + print('selectedRuleIds: $selectedRuleIds'); + print('selectedGejalaIds: $selectedGejalaIds'); + print('nilaiPakarList: $nilaiPakarList'); + }); + } catch (e) { + print("Gagal memuat data rule: $e"); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text("Gagal memuat data rule: $e"))); + } + } + + // Fungsi untuk fetch data dari API + Future fetchData() async { + setState(() { + isLoading = true; // Mengatur status loading saat mulai ambil data + }); + + try { + // Ambil data dari API + final hamaData = await api.getHama(); + final penyakitData = await api.getPenyakit(); + final gejalaData = await api.getGejala(); + + // Debugging: Cek apakah data yang diterima dari API + print("Hama Data: $hamaData"); + print("Penyakit Data: $penyakitData"); + print("Gejala Data: $gejalaData"); + + // Pengecekan jika data kosong + if (hamaData.isEmpty || penyakitData.isEmpty || gejalaData.isEmpty) { + print("Data kosong, periksa API atau koneksi."); + } + + // Update data dan status loading + setState(() { + hamaList = hamaData; + penyakitList = penyakitData; + gejalaList = gejalaData; + isLoading = false; // Mengubah status loading setelah data diterima + }); + } catch (e) { + // Menangani error jika fetch gagal + print("Error fetching data: $e"); + + setState(() { + isLoading = + false; // Mengubah status loading selesai meskipun terjadi error + }); + } + } + + @override + void initState() { + super.initState(); + fetchData(); // Panggil fetchData saat halaman dibuka pertama kali + + // Inisialisasi dari widget parent + if (widget.isEditing) { + selectedHamaId = widget.selectedHamaId; + selectedPenyakitId = widget.selectedPenyakitId; + + // Copy nilai dari widget ke state + if (widget.selectedRuleIds.isNotEmpty) { + selectedRuleIds = List.from(widget.selectedRuleIds); + } + if (widget.selectedGejalaIds.isNotEmpty) { + selectedGejalaIds = List.from(widget.selectedGejalaIds); + } + if (widget.nilaiPakarList.isNotEmpty) { + nilaiPakarList = List.from(widget.nilaiPakarList); + } + } + } + + void updateRules() async { + if (selectedRuleIds.length != selectedGejalaIds.length || + selectedRuleIds.length != nilaiPakarList.length) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("Data rule tidak sinkron. Silakan cek kembali."), + ), + ); + return; + } + + try { + for (int i = 0; i < selectedGejalaIds.length; i++) { + final idRule = selectedRuleIds[i]; + final idGejala = selectedGejalaIds[i]; + final nilai = nilaiPakarList[i]; + + if (idRule == null || idGejala == null) { + print("Lewat karena data null pada index ke-$i"); + continue; + } + + http.Response response; + + if (selectedPenyakitId != null) { + response = await ApiService.updateRulePenyakit( + id: idRule, + idGejala: idGejala, + idPenyakit: selectedPenyakitId!, + nilaiPakar: nilai, + ); + } else { + response = await ApiService.updateRuleHama( + id: idRule, + idGejala: idGejala, + idHama: selectedHamaId!, + nilaiPakar: nilai, + ); + } + + if (response.statusCode != 200 && response.statusCode != 201) { + throw Exception("Gagal mengupdate rule"); + } + } + + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text("Data berhasil diperbarui"))); + Navigator.pop(context); + } catch (e) { + print('Gagal memperbarui data: $e'); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text("Gagal memperbarui data"))); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text("Tambah Rule")), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: + isLoading + ? Center(child: CircularProgressIndicator()) + : Card( + elevation: 5, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: ListView( + children: [ + // Pilih Hama + Text("Pilih Hama"), + DropdownButton( + isExpanded: true, + value: selectedHamaId, + hint: Text('Pilih Hama'), + items: + hamaList.isNotEmpty + ? hamaList.map>((hama) { + return DropdownMenuItem( + value: hama['id'], + child: Text(hama['nama']), + ); + }).toList() + : [ + DropdownMenuItem( + value: null, + child: Text("Data tidak tersedia"), + ), + ], + onChanged: (value) { + setState(() { + selectedHamaId = value; + }); + }, + ), + SizedBox(height: 16), + + // Pilih Penyakit + Text("Pilih Penyakit"), + DropdownButton( + isExpanded: true, + value: selectedPenyakitId, + hint: Text('Pilih Penyakit'), + items: + penyakitList.isNotEmpty + ? penyakitList.map>(( + penyakit, + ) { + return DropdownMenuItem( + value: penyakit['id'], + child: Text(penyakit['nama']), + ); + }).toList() + : [ + DropdownMenuItem( + value: null, + child: Text("Data tidak tersedia"), + ), + ], + onChanged: (value) { + setState(() { + selectedPenyakitId = value; + }); + }, + ), + SizedBox(height: 16), + + // Pilih Gejala dan Nilai Pakar + Text("Pilih Gejala"), + ...List.generate( + selectedGejalaIds.length, + (index) => Card( + elevation: 3, + margin: EdgeInsets.only(bottom: 16), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + // Dropdown untuk gejala + Expanded( + child: DropdownButton( + isExpanded: true, + value: selectedGejalaIds[index], + hint: Text('Pilih Gejala'), + items: + gejalaList.isNotEmpty + ? gejalaList.map< + DropdownMenuItem + >((gejala) { + return DropdownMenuItem( + value: gejala['id'], + child: Text(gejala['nama']), + ); + }).toList() + : [ + DropdownMenuItem( + value: null, + child: Text( + "Data tidak tersedia", + ), + ), + ], + onChanged: (value) { + setState(() { + selectedGejalaIds[index] = value; + }); + }, + ), + ), + + // Input nilai pakar + SizedBox(width: 16), + SizedBox( + width: 80, + child: TextField( + keyboardType: TextInputType.number, + // Gunakan TextEditingController untuk menampilkan nilai awal + controller: TextEditingController( + text: + nilaiPakarList.length > index + ? nilaiPakarList[index] + .toString() + : "0.5", + ), + decoration: InputDecoration( + labelText: "Nilai Pakar", + border: OutlineInputBorder(), + ), + onChanged: (value) { + setState(() { + if (value.isNotEmpty) { + // Pastikan index ada dalam range + if (nilaiPakarList.length <= + index) { + // Tambahkan nilai baru jika index belum ada + nilaiPakarList.add( + double.tryParse(value) ?? 0.5, + ); + } else { + // Update nilai jika index sudah ada + nilaiPakarList[index] = + double.tryParse(value) ?? 0.5; + } + } + }); + }, + ), + ), + + // Tombol untuk menghapus gejala + IconButton( + icon: Icon(Icons.remove_circle_outline), + onPressed: () { + setState(() { + selectedGejalaIds.removeAt(index); + nilaiPakarList.removeAt(index); + }); + }, + ), + ], + ), + ), + ), + ), + + // Tombol untuk menambah gejala + ElevatedButton( + onPressed: () { + setState(() { + selectedGejalaIds.add(null); + nilaiPakarList.add( + 0.5, + ); // Menambahkan nilai pakar default + }); + }, + child: Text('Tambah Gejala'), + ), + + SizedBox(height: 20), + + // Tombol untuk edit rule + ElevatedButton( + onPressed: () { + // Panggil fungsi saveRules untuk menyimpan data + updateRules(); + }, + child: Text('Perbarui Rule'), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/frontend/lib/admin/rule_page.dart b/frontend/lib/admin/rule_page.dart index f9c71a3..2f8f7bf 100644 --- a/frontend/lib/admin/rule_page.dart +++ b/frontend/lib/admin/rule_page.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:frontend/admin/edit_rule_page.dart'; import 'package:http/http.dart' as http; import 'package:frontend/api_services/api_services.dart'; import 'tambah_rule_page.dart'; +import 'edit_hama_page.dart'; class RulePage extends StatefulWidget { const RulePage({Key? key}) : super(key: key); @@ -241,29 +243,49 @@ class _RulePageState extends State { color: Colors.orange, ), onPressed: () { - if (rule != null && rule.id != null) { + if (rule != null && + rule['id'] != null && + rule['id_gejala'] != null && + rule['nilai_pakar'] != null) { Navigator.push( context, MaterialPageRoute( builder: - (context) => TambahRulePage( + (context) => EditRulePage( isEditing: true, isEditingHama: true, - selectedRuleIds: [rule.id], + selectedRuleIds: [ + rule['id'] as int, + ], selectedGejalaIds: [ - rule.idGejala, + rule['id_gejala'] as int, ], nilaiPakarList: [ - rule.nilaiPakar, + (rule['nilai_pakar'] as num) + .toDouble(), ], - selectedHamaId: rule.idHama, + selectedHamaId: + rule['id_hama'] + as int?, + selectedPenyakitId: rule['id_penyakit'] as int?, // Tambahkan type cast ke int? ), ), ); } else { - print( - 'Data rule tidak lengkap atau null', + // Tampilkan pesan error jika data rule tidak lengkap + ScaffoldMessenger.of( + context, + ).showSnackBar( + SnackBar( + content: Text( + "Data rule tidak lengkap atau tidak valid", + ), + backgroundColor: Colors.red, + ), ); + + // Debug info + print("Rule data: $rule"); } }, ), diff --git a/frontend/lib/admin/tambah_rule_page.dart b/frontend/lib/admin/tambah_rule_page.dart index d84220c..539538b 100644 --- a/frontend/lib/admin/tambah_rule_page.dart +++ b/frontend/lib/admin/tambah_rule_page.dart @@ -27,7 +27,6 @@ class TambahRulePage extends StatefulWidget { } class _TambahRulePageState extends State { - int? selectedHamaId; int? selectedPenyakitId; List selectedGejalaIds = [null]; @@ -45,25 +44,37 @@ class _TambahRulePageState extends State { List> penyakitList = []; List> gejalaList = []; - void loadRulesForEditing() async { - try { - final fetchedRules = isEditing - ? await api.getRulesHama() - : await api.getRulesPenyakit(); - - setState(() { - selectedRuleIds = fetchedRules.map((rule) => rule['id']).toList(); - selectedGejalaIds = fetchedRules.map((rule) => rule['id_gejala']).toList(); - nilaiPakarList = fetchedRules.map((rule) => (rule['nilai_pakar'] as num).toDouble()).toList(); - }); - } catch (e) { - print("Gagal memuat data rule: $e"); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("Gagal memuat data rule")), - ); - } -} - + // void loadRulesForEditing() async { + // try { + // final fetchedRules = + // isEditing ? await api.getRulesHama() : await api.getRulesPenyakit(); + // setState(() { + // final validRules = + // fetchedRules + // .where( + // (rule) => + // rule != null && + // rule.containsKey('id') && + // rule.containsKey('id_gejala') && + // rule.containsKey('nilai_pakar') && + // rule['id'] != null && + // rule['id_gejala'] != null && + // rule['nilai_pakar'] != null, + // ) + // .toList(); + // selectedRuleIds = fetchedRules.map((rule) => rule['id'] ?? 0).toList(); + // selectedGejalaIds = validRules.map((rule) => rule['id_gejala']).toList(); + // nilaiPakarList = validRules.map((rule) => (rule['nilai_pakar'] as num).toDouble()).toList(); + // }); + // print('Fetched Rules: $fetchedRules'); + // print('First Rule: ${fetchedRules.first}'); + // } catch (e) { + // print("Gagal memuat data rule: $e"); + // ScaffoldMessenger.of( + // context, + // ).showSnackBar(SnackBar(content: Text("Gagal memuat data rule"))); + // } + // } // Fungsi untuk fetch data dari API Future fetchData() async { @@ -162,57 +173,56 @@ class _TambahRulePageState extends State { } } - void updateRules() async { - if (selectedPenyakitId == null && selectedHamaId == null) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("Pilih minimal satu: Penyakit atau Hama")), - ); - return; - } + // void updateRules() async { + // if (selectedPenyakitId == null && selectedHamaId == null) { + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar(content: Text("Pilih minimal satu: Penyakit atau Hama")), + // ); + // return; + // } - try { - for (int i = 0; i < selectedGejalaIds.length; i++) { - final idRule = selectedRuleIds[i]; - final idGejala = selectedGejalaIds[i]; - final nilai = nilaiPakarList[i]; + // try { + // for (int i = 0; i < selectedGejalaIds.length; i++) { + // final idRule = selectedRuleIds[i]; + // final idGejala = selectedGejalaIds[i]; + // final nilai = nilaiPakarList[i]; - if (idRule != null && idGejala != null) { - http.Response response; + // if (idRule != null && idGejala != null) { + // http.Response response; - if (selectedPenyakitId != null) { - response = await ApiService.updateRulePenyakit( - id: idRule, - idGejala: idGejala, - idPenyakit: selectedPenyakitId, - nilaiPakar: nilai, - ); - } else { - response = await ApiService.updateRuleHama( - id: idRule, - idGejala: idGejala, - idHama: selectedHamaId, - nilaiPakar: nilai, - ); - } + // if (selectedPenyakitId != null) { + // response = await ApiService.updateRulePenyakit( + // id: idRule, + // idGejala: idGejala, + // idPenyakit: selectedPenyakitId, + // nilaiPakar: nilai, + // ); + // } else { + // response = await ApiService.updateRuleHama( + // id: idRule, + // idGejala: idGejala, + // idHama: selectedHamaId, + // nilaiPakar: nilai, + // ); + // } - if (response.statusCode != 200 && response.statusCode != 201) { - throw Exception("Gagal mengupdate rule"); - } - } - } - - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("Data berhasil diperbarui")), - ); - Navigator.pop(context); - } catch (e) { - print('Gagal memperbarui data: $e'); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("Gagal memperbarui data")), - ); - } -} + // if (response.statusCode != 200 && response.statusCode != 201) { + // throw Exception("Gagal mengupdate rule"); + // } + // } + // } + // ScaffoldMessenger.of( + // context, + // ).showSnackBar(SnackBar(content: Text("Data berhasil diperbarui"))); + // Navigator.pop(context); + // } catch (e) { + // print('Gagal memperbarui data: $e'); + // ScaffoldMessenger.of( + // context, + // ).showSnackBar(SnackBar(content: Text("Gagal memperbarui data"))); + // } + // } @override Widget build(BuildContext context) { diff --git a/frontend/lib/api_services/api_services.dart b/frontend/lib/api_services/api_services.dart index ea0ac20..241dab1 100644 --- a/frontend/lib/api_services/api_services.dart +++ b/frontend/lib/api_services/api_services.dart @@ -7,8 +7,7 @@ class ApiService { static const String gejalaUrl = 'http://localhost:5000/api/gejala'; static const String hamaUrl = 'http://localhost:5000/api/hama'; static const String penyakitUrl = 'http://localhost:5000/api/penyakit'; - static const String rulesPenyakitUrl = - 'http://localhost:5000/api/rules_penyakit'; + static const String rulesPenyakitUrl ='http://localhost:5000/api/rules_penyakit'; static const String rulesHamaUrl = 'http://localhost:5000/api/rules_hama'; // Fungsi Login (dengan perbaikan)