import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import 'package:image_picker/image_picker.dart'; import 'package:http_parser/http_parser.dart'; class ApiService { static const String baseUrl = 'http://localhost:5000/api/auth'; 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 rulesHamaUrl = 'http://localhost:5000/api/rules_hama'; static const String userUrl = 'http://localhost:5000/api/users'; static const String diagnosaUrl = 'http://localhost:5000/api/diagnosa'; static const String historiUrl = 'http://localhost:5000/api/histori'; static const Duration timeout = Duration(seconds: 15); /// Fungsi untuk mengirim gejala dan menerima hasil diagnosa Future> diagnosa(List gejalaIds) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); final token = prefs.getString('token'); List parsedGejala; try { // Coba konversi ke integer jika bisa parsedGejala = gejalaIds.map((id) => int.parse(id)).toList(); } catch (e) { print("Konversi ke integer gagal, gunakan string ID."); parsedGejala = gejalaIds; } final response = await http.post( Uri.parse(diagnosaUrl), headers: { 'Content-Type': 'application/json', if (token != null) 'Authorization': 'Bearer $token', }, body: json.encode({'gejala': parsedGejala}), ).timeout(timeout); if (response.statusCode == 200) { return json.decode(response.body); } else { throw Exception('Gagal melakukan diagnosa: ${response.statusCode} - ${response.body}'); } } Future>> getHistoriDiagnosa(String userId) async { try { // Ambil token dari SharedPreferences final SharedPreferences prefs = await SharedPreferences.getInstance(); final token = prefs.getString('token'); if (token == null || token.isEmpty) { throw Exception("Token tidak valid"); } final url = '$historiUrl/user/$userId'; print("Fetching histori from URL: $url"); final response = await http.get( Uri.parse(url), headers: {'Content-Type': 'application/json'}, ); print("Response Status Code: ${response.statusCode}"); print("Response Body: ${response.body}"); if (response.statusCode == 200) { final Map responseData = json.decode(response.body); if (responseData.containsKey('data') && responseData['data'] is List) { return List>.from(responseData['data']); } else { throw Exception('Format respons tidak valid.'); } } else { throw Exception('Gagal memuat histori: ${response.statusCode}'); } } catch (e) { print("Error fetching data: $e"); throw Exception('Terjadi kesalahan saat mengambil histori: $e'); } } Future>> fetchHistoriDenganDetail(String userId) async { try { // Panggil API untuk mendapatkan data histori final historiResponse = await getHistoriDiagnosa(userId); // Tambahkan: Panggil API untuk mendapatkan data user final userData = await getUserById(userId); final String userName = userData != null ? userData['name'] ?? "User $userId" : "User $userId"; Future>> fetchHistoriDenganDetail(String userId) async { try { // Panggil API untuk mendapatkan data histori final historiResponse = await getHistoriDiagnosa(userId); // Perbaiki cara mendapatkan data user final userData = await getUserById(userId); // Pastikan data user ada dan nama diambil dengan benar final String userName = userData != null && userData['name'] != null ? userData['name'] : "User $userId"; print("User Data received: $userData"); // Debug log // Proses data histori List> result = historiResponse.map((histori) { final gejala = histori['gejala'] ?? {}; final penyakit = histori['penyakit'] ?? {}; final hama = histori['hama'] ?? {}; return { "id": histori['id'], "userId": histori['userId'], "name": userName, // Menggunakan nama yang sudah diambil "tanggal_diagnosa": histori['tanggal_diagnosa'], "hasil": histori['hasil'], "gejala_nama": gejala['nama'] ?? "Tidak diketahui", "penyakit_nama": penyakit['nama'], "hama_nama": hama['nama'], }; }).toList(); print("Processed Histori Data with Username: $result"); // Debug log return result; } catch (e) { print("Error fetching histori dengan detail: $e"); return []; } } // Proses data histori List> result = historiResponse.map((histori) { // Tangani properti null dengan default value final gejala = histori['gejala'] ?? {}; final penyakit = histori['penyakit'] ?? {}; final hama = histori['hama'] ?? {}; return { "id": histori['id'], "userId": histori['userId'], "name": userName, // Tambahkan nama user ke hasil "tanggal_diagnosa": histori['tanggal_diagnosa'], "hasil": histori['hasil'], "gejala_nama": gejala['nama'] ?? "Tidak diketahui", "penyakit_nama": penyakit['nama'], "hama_nama": hama['nama'], }; }).toList(); print("Processed Histori Data with Username: $result"); return result; } catch (e) { print("Error fetching histori dengan detail: $e"); return []; } } // Tambahkan fungsi getToken Future getToken() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.getString('token'); } // Modifikasi fungsi getAllHistori Future>> getAllHistori() async { try { final token = await getToken(); if (token == null) { throw Exception('Token tidak ditemukan'); } final response = await http.get( Uri.parse('$historiUrl'), // Gunakan historiUrl bukan baseUrl/histori headers: { "Content-Type": "application/json", "Authorization": "Bearer $token" }, ); if (response.statusCode == 200) { final Map responseData = jsonDecode(response.body); final List historiList = responseData['data']; return historiList.map((histori) => histori as Map).toList(); } else { throw Exception( jsonDecode(response.body)['message'] ?? 'Gagal mengambil data histori' ); } } catch (e) { print('Error getting histori: $e'); throw Exception('Gagal mengambil data histori: $e'); } } // Fungsi Login (dengan perbaikan) static Future> loginUser( String email, String password, ) async { try { final response = await http.post( Uri.parse("$baseUrl/login"), headers: {"Content-Type": "application/json"}, body: jsonEncode({'email': email, 'password': password}), ); print("Response Status: ${response.statusCode}"); print("Response Body: ${response.body}"); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); // Simpan userId ke SharedPreferences final SharedPreferences prefs = await SharedPreferences.getInstance(); print("User ID dari respons login: ${responseData['userId']}"); // Tambahkan log await prefs.setString('userId', responseData['userId'].toString()); return responseData; } else { throw Exception("Login gagal: ${response.body}"); } } catch (e) { print("Error: $e"); throw Exception("Terjadi kesalahan saat login"); } } // Fungsi Logout static Future logoutUser() async { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.remove('token'); await prefs.remove('role'); } // Fungsi Cek Login static Future checkLoginStatus() async { SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.getString('role'); // Return role jika login } // Ambil semua gejala Future>> getGejala() async { try { final response = await http.get(Uri.parse(gejalaUrl)); if (response.statusCode == 200) { return List>.from(jsonDecode(response.body)); } else { throw Exception('Gagal mengambil data gejala'); } } catch (e) { print('Error getGejala: $e'); throw Exception('Gagal mengambil data gejala'); } } // Tambah gejala baru (kode otomatis) Future> createGejala(String nama) async { try { final response = await http.post( Uri.parse(gejalaUrl), headers: {"Content-Type": "application/json"}, body: jsonEncode({"nama": nama}), ); if (response.statusCode == 201) { return jsonDecode(response.body); } else { throw Exception('Gagal menambahkan gejala'); } } catch (e) { print('Error createGejala: $e'); throw Exception('Gagal menambahkan gejala'); } } // Update gejala berdasarkan ID Future> updateGejala(int id, String nama) async { try { final response = await http.put( Uri.parse('$gejalaUrl/$id'), headers: {"Content-Type": "application/json"}, body: jsonEncode({"nama": nama}), ); if (response.statusCode == 200) { return jsonDecode(response.body); } else { throw Exception('Gagal mengupdate gejala'); } } catch (e) { print('Error updateGejala: $e'); throw Exception('Gagal mengupdate gejala'); } } // Hapus gejala berdasarkan ID Future deleteGejala(int id) async { try { final response = await http.delete(Uri.parse('$gejalaUrl/$id')); if (response.statusCode != 200) { throw Exception('Gagal menghapus gejala'); } } catch (e) { print('Error deleteGejala: $e'); throw Exception('Gagal menghapus gejala'); } } // Ambil semua hama Future>> getHama() async { try { final response = await http.get(Uri.parse(hamaUrl)).timeout(timeout); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); // Pastikan "data" ada dan berupa List if (responseData is Map && responseData.containsKey("data")) { final List data = responseData["data"]; return List>.from( data.map((item) => Map.from(item)), ); } else { throw Exception("Format respons API tidak sesuai"); } } else { print('Error response: ${response.statusCode} - ${response.body}'); throw Exception("Gagal mengambil data hama (Status: ${response.statusCode})"); } } catch (e) { print("Error getHama: $e"); throw Exception("Gagal mengambil data hama: $e"); } } Future> getHamaById(int id) async { try { final response = await http.get(Uri.parse('$hamaUrl/$id')); print('Fetching hama with ID $id from $hamaUrl/$id'); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); print('Response data: $responseData'); // Periksa format respons if (responseData is Map && responseData.containsKey("data")) { final data = responseData["data"]; return Map.from(data); } else if (responseData is Map) { // Jika langsung mengembalikan objek tanpa wrapper "data" return responseData; } else { throw Exception("Format respons API tidak sesuai"); } } else { print('Error response: ${response.statusCode} - ${response.body}'); throw Exception( "Gagal mengambil data hama dengan ID $id (Status: ${response.statusCode})", ); } } catch (e) { print("Error getHamaById: $e"); throw Exception("Gagal mengambil data hama dengan ID $id: $e"); } } // Fungsi untuk mendapatkan URL gambar hama String getHamaImageUrl(int id) { return '$hamaUrl/$id/image'; } // Fungsi untuk mengecek apakah gambar tersedia Future isHamaImageAvailable(int id) async { try { final url = Uri.parse(getHamaImageUrl(id)); print('Checking image availability: $url'); final response = await http.head(url); print('Image availability status: ${response.statusCode}'); return response.statusCode == 200; } catch (e) { print("Error checking image availability: $e"); return false; } } // Fungsi untuk mengambil gambar hama sebagai bytes Future getHamaImageBytes(int id) async { try { final url = Uri.parse(getHamaImageUrl(id)); print('Fetching image bytes from: $url'); final response = await http.get(url); if (response.statusCode == 200) { return response.bodyBytes; } else { print('Failed to get image bytes: ${response.statusCode}'); print( 'Response body: ${response.body}', ); // Tambahkan ini untuk melihat pesan error return null; } } catch (e) { print('Error getting image bytes: $e'); return null; } } Future getHamaImageBytesByFilename(String filename) async { try { final url = Uri.parse('http://localhost:5000/image_hama/$filename'); print('Fetching image from: $url'); final response = await http.get(url); if (response.statusCode == 200) { return response.bodyBytes; } else { print('Failed to fetch image. Status: ${response.statusCode}'); print('Response body: ${response.body}'); return null; } } catch (e) { print('Error fetching image by filename: $e'); return null; } } // Tambah hama baru (kode otomatis) Future> createHama( String nama, String deskripsi, String penanganan, XFile? pickedFile, double nilai_pakar ) async { try { var uri = Uri.parse(hamaUrl); var request = http.MultipartRequest('POST', uri); request.fields['nama'] = nama; request.fields['deskripsi'] = deskripsi; request.fields['penanganan'] = penanganan; request.fields['nilai_pakar'] = nilai_pakar.toString(); print('Mengirim request ke: $uri'); print('Dengan fields: ${request.fields}'); if (pickedFile != null) { String mimeType = 'image/jpeg'; String fileName = pickedFile.name; if (fileName.isEmpty) { fileName = pickedFile.path.split('/').last; } if (fileName.toLowerCase().endsWith('.png')) { mimeType = 'image/png'; } else if (fileName.toLowerCase().endsWith('.jpg') || fileName.toLowerCase().endsWith('.jpeg')) { mimeType = 'image/jpeg'; } final bytes = await pickedFile.readAsBytes(); request.files.add( http.MultipartFile.fromBytes( 'foto', // Sesuaikan dengan field name yang diterima backend bytes, filename: fileName, contentType: MediaType.parse(mimeType), ), ); print('Menambahkan file: $fileName (${bytes.length} bytes)'); } else { print('Tidak ada file yang dilampirkan'); } var streamedResponse = await request.send(); var response = await http.Response.fromStream(streamedResponse); print('Status response: ${response.statusCode}'); print('Body response: ${response.body}'); if (response.statusCode == 201) { return jsonDecode(response.body); } else { String errorMessage = 'Gagal menambahkan hama (kode: ${response.statusCode})'; try { var errorBody = jsonDecode(response.body); if (errorBody is Map && errorBody.containsKey('message')) { errorMessage = errorBody['message']; } } catch (e) { if (response.body.isNotEmpty) { errorMessage = response.body; } } throw Exception(errorMessage); } } catch (e) { print('Error dalam createHama: $e'); throw Exception('Gagal menambahkan hama: $e'); } } // Update hama berdasarkan ID Future> updateHama( int id, String nama, String deskripsi, String penanganan, XFile? pickedFile, double nilai_pakar ) async { try { var uri = Uri.parse('$hamaUrl/$id'); var request = http.MultipartRequest('PUT', uri); // Tambahkan fields untuk data teks request.fields['nama'] = nama; request.fields['deskripsi'] = deskripsi; request.fields['penanganan'] = penanganan; request.fields['nilai_pakar'] = nilai_pakar.toString(); // Log untuk debugging print('Mengirim request ke: $uri'); print('Dengan fields: ${request.fields}'); if (pickedFile != null) { // Dapatkan tipe MIME berdasarkan ekstensi file String mimeType = 'image/jpeg'; // Default String fileName = pickedFile.name; if (fileName.isEmpty) { fileName = pickedFile.path.split('/').last; } if (fileName.toLowerCase().endsWith('.png')) { mimeType = 'image/png'; } else if (fileName.toLowerCase().endsWith('.jpg') || fileName.toLowerCase().endsWith('.jpeg')) { mimeType = 'image/jpeg'; } // Baca file sebagai bytes final bytes = await pickedFile.readAsBytes(); // Tambahkan file ke request dengan tipe yang tepat request.files.add( http.MultipartFile.fromBytes( 'foto', // Nama field ini harus sama dengan yang diharapkan backend bytes, filename: fileName, contentType: MediaType.parse(mimeType), ), ); print('Menambahkan file: $fileName (${bytes.length} bytes)'); } else { print('Tidak ada file yang dilampirkan'); } // Kirim request var streamedResponse = await request.send(); var response = await http.Response.fromStream(streamedResponse); // Debug response print('Status response: ${response.statusCode}'); print('Body response: ${response.body}'); if (response.statusCode == 200) { return jsonDecode(response.body); } else { // Coba ambil pesan error dari response body String errorMessage = 'Gagal mengupdate hama (kode: ${response.statusCode})'; try { var errorBody = jsonDecode(response.body); if (errorBody is Map && errorBody.containsKey('message')) { errorMessage = errorBody['message']; } } catch (e) { // Jika gagal parse JSON, gunakan response body langsung if (response.body.isNotEmpty) { errorMessage = response.body; } } throw Exception(errorMessage); } } catch (e) { print('Error dalam updateHama: $e'); throw Exception('Gagal mengupdate hama: $e'); } } // Hapus hama berdasarkan ID Future deleteHama(int id) async { try { final response = await http.delete(Uri.parse('$hamaUrl/$id')); if (response.statusCode != 200) { throw Exception('Gagal menghapus hama'); } } catch (e) { print('Error deleteHama: $e'); throw Exception('Gagal menghapus hama'); } } // Ambil semua penyakit Future>> getPenyakit() async { try { final response = await http.get(Uri.parse(ApiService.penyakitUrl)); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); // Pastikan "data" ada dan berupa List if (responseData is Map && responseData.containsKey("data")) { final List data = responseData["data"]; return List>.from( data.map((item) => Map.from(item)), ); } else { throw Exception("Format respons API tidak sesuai"); } } else { throw Exception("Gagal mengambil data penyakit"); } } catch (e) { print("Error getHama: $e"); throw Exception("Gagal mengambil data penyakit"); } } Future> getPenyakitById(int id) async { try { final response = await http.get(Uri.parse('$penyakitUrl/$id')); print('Fetching penyakit with ID $id from $penyakitUrl/$id'); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); print('Response data: $responseData'); // Periksa format respons if (responseData is Map && responseData.containsKey("data")) { final data = responseData["data"]; return Map.from(data); } else if (responseData is Map) { // Jika langsung mengembalikan objek tanpa wrapper "data" return responseData; } else { throw Exception("Format respons API tidak sesuai"); } } else { print('Error response: ${response.statusCode} - ${response.body}'); throw Exception( "Gagal mengambil data penyakit dengan ID $id (Status: ${response.statusCode})", ); } } catch (e) { print("Error getPenyakitById: $e"); throw Exception("Gagal mengambil data penyakit dengan ID $id: $e"); } } // Fungsi untuk mendapatkan URL gambar penyakit String getPenyakitImageUrl(int id) { return '$penyakitUrl/$id/image'; } // Fungsi untuk mengecek apakah gambar tersedia Future isPenyakitImageAvailable(int id) async { try { final url = Uri.parse(getHamaImageUrl(id)); print('Checking image availability: $url'); final response = await http.head(url); print('Image availability status: ${response.statusCode}'); return response.statusCode == 200; } catch (e) { print("Error checking image availability: $e"); return false; } } Future getPenyakitImageBytes(int id) async { try { final url = Uri.parse(getPenyakitImageUrl(id)); print('Fetching image bytes from: $url'); final response = await http.get(url); if (response.statusCode == 200) { return response.bodyBytes; } else { print('Failed to get image bytes: ${response.statusCode}'); print( 'Response body: ${response.body}', ); // Tambahkan ini untuk melihat pesan error return null; } } catch (e) { print('Error getting image bytes: $e'); return null; } } Future getPenyakitImageBytesByFilename(String filename) async { try { final url = Uri.parse('http://localhost:5000/image_penyakit/$filename'); print('Fetching image from: $url'); final response = await http.get(url); if (response.statusCode == 200) { return response.bodyBytes; } else { print('Failed to fetch image. Status: ${response.statusCode}'); print('Response body: ${response.body}'); return null; } } catch (e) { print('Error fetching image by filename: $e'); return null; } } // Tambah penyakit baru (kode otomatis) Future> createPenyakit( String nama, String deskripsi, String penanganan, XFile? pickedFile, double nilai_pakar ) async { try { var uri = Uri.parse(penyakitUrl); var request = http.MultipartRequest('POST', uri); request.fields['nama'] = nama; request.fields['deskripsi'] = deskripsi; request.fields['penanganan'] = penanganan; request.fields['nilai_pakar'] = nilai_pakar.toString(); print('Mengirim request ke: $uri'); print('Dengan fields: ${request.fields}'); if (pickedFile != null) { String mimeType = 'image/jpeg'; String fileName = pickedFile.name; if (fileName.isEmpty) { fileName = pickedFile.path.split('/').last; } if (fileName.toLowerCase().endsWith('.png')) { mimeType = 'image/png'; } else if (fileName.toLowerCase().endsWith('.jpg') || fileName.toLowerCase().endsWith('.jpeg')) { mimeType = 'image/jpeg'; } final bytes = await pickedFile.readAsBytes(); request.files.add( http.MultipartFile.fromBytes( 'foto', // Sesuaikan dengan field name yang diterima backend bytes, filename: fileName, contentType: MediaType.parse(mimeType), ), ); print('Menambahkan file: $fileName (${bytes.length} bytes)'); } else { print('Tidak ada file yang dilampirkan'); } var streamedResponse = await request.send(); var response = await http.Response.fromStream(streamedResponse); print('Status response: ${response.statusCode}'); print('Body response: ${response.body}'); if (response.statusCode == 201) { return jsonDecode(response.body); } else { String errorMessage = 'Gagal menambahkan penyakit (kode: ${response.statusCode})'; try { var errorBody = jsonDecode(response.body); if (errorBody is Map && errorBody.containsKey('message')) { errorMessage = errorBody['message']; } } catch (e) { if (response.body.isNotEmpty) { errorMessage = response.body; } } throw Exception(errorMessage); } } catch (e) { print('Error dalam createPenyakit: $e'); throw Exception('Gagal menambahkan penyakit: $e'); } } // Update penyakit berdasarkan ID Future> updatePenyakit( int id, String nama, String deskripsi, String penanganan, XFile? pickedFile, double nilai_pakar ) async { try { var uri = Uri.parse('$penyakitUrl/$id'); var request = http.MultipartRequest('PUT', uri); // Tambahkan fields untuk data teks request.fields['nama'] = nama; request.fields['deskripsi'] = deskripsi; request.fields['penanganan'] = penanganan; request.fields['nilai_pakar'] = nilai_pakar.toString(); // Log untuk debugging print('Mengirim request ke: $uri'); print('Dengan fields: ${request.fields}'); if (pickedFile != null) { // Dapatkan tipe MIME berdasarkan ekstensi file String mimeType = 'image/jpeg'; // Default String fileName = pickedFile.name; if (fileName.isEmpty) { fileName = pickedFile.path.split('/').last; } if (fileName.toLowerCase().endsWith('.png')) { mimeType = 'image/png'; } else if (fileName.toLowerCase().endsWith('.jpg') || fileName.toLowerCase().endsWith('.jpeg')) { mimeType = 'image/jpeg'; } // Baca file sebagai bytes final bytes = await pickedFile.readAsBytes(); // Tambahkan file ke request dengan tipe yang tepat request.files.add( http.MultipartFile.fromBytes( 'foto', // Nama field ini harus sama dengan yang diharapkan backend bytes, filename: fileName, contentType: MediaType.parse(mimeType), ), ); print('Menambahkan file: $fileName (${bytes.length} bytes)'); } else { print('Tidak ada file yang dilampirkan'); } // Kirim request var streamedResponse = await request.send(); var response = await http.Response.fromStream(streamedResponse); // Debug response print('Status response: ${response.statusCode}'); print('Body response: ${response.body}'); if (response.statusCode == 200) { return jsonDecode(response.body); } else { // Coba ambil pesan error dari response body String errorMessage = 'Gagal mengupdate hama (kode: ${response.statusCode})'; try { var errorBody = jsonDecode(response.body); if (errorBody is Map && errorBody.containsKey('message')) { errorMessage = errorBody['message']; } } catch (e) { // Jika gagal parse JSON, gunakan response body langsung if (response.body.isNotEmpty) { errorMessage = response.body; } } throw Exception(errorMessage); } } catch (e) { print('Error dalam updateHama: $e'); throw Exception('Gagal mengupdate hama: $e'); } } // Hapus penyakit berdasarkan ID Future deletePenyakit(int id) async { try { final response = await http.delete(Uri.parse('$penyakitUrl/$id')); if (response.statusCode != 200) { throw Exception('Gagal menghapus penyakit'); } } catch (e) { print('Error deletePenyakit: $e'); throw Exception('Gagal menghapus penyakit'); } } //registrasi Future registerUser({ required String name, required String email, required String password, required String alamat, required String nomorTelepon, }) async { final response = await http.post( Uri.parse('$baseUrl/register'), // Endpoint register headers: {"Content-Type": "application/json"}, body: jsonEncode({ 'name': name, 'email': email, 'password': password, 'alamat': alamat, 'nomorTelepon': nomorTelepon, 'role': 'user', // role default }), ); if (response.statusCode != 201) { throw Exception( jsonDecode(response.body)['message'] ?? 'Gagal mendaftar', ); } } // Fungsi untuk mengirim kode verifikasi Future sendResetCode({ required String email, }) async { try { final response = await http.post( Uri.parse('$baseUrl/send-reset-code'), headers: {"Content-Type": "application/json"}, body: jsonEncode({ 'email': email, }), ); if (response.statusCode != 200) { throw Exception( jsonDecode(response.body)['message'] ?? 'Gagal mengirim kode verifikasi', ); } } catch (e) { print('Error sending reset code: $e'); throw Exception('Gagal mengirim kode verifikasi: $e'); } } // Fungsi untuk reset password dengan kode verifikasi Future resetPasswordWithCode({ required String code, required String password, }) async { try { final response = await http.post( Uri.parse('$baseUrl/reset-password'), headers: {"Content-Type": "application/json"}, body: jsonEncode({ 'code': code, 'password': password, }), ); if (response.statusCode != 200) { throw Exception( jsonDecode(response.body)['message'] ?? 'Gagal reset password', ); } } catch (e) { print('Error resetting password: $e'); throw Exception('Gagal reset password: $e'); } } Future verifyResetCode({required String email, required String code}) async { try { final response = await http.post( Uri.parse('$baseUrl/reset-password'), headers: {"Content-Type": "application/json"}, body: jsonEncode({ 'email': email, 'resetToken': code, }), ); if (response.statusCode == 200) { // Jika status code 200, berarti kode valid return true; } else { // Jika status code bukan 200, kode tidak valid final error = jsonDecode(response.body); throw error['message'] ?? 'Kode verifikasi tidak valid'; } } catch (e) { throw e.toString(); } } // Create Rule penyakit static Future createRulePenyakit({ required int idGejala, int? idPenyakit, required double nilaiPakar, }) async { final response = await http.post( Uri.parse('$rulesPenyakitUrl'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'id_gejala': idGejala, 'id_penyakit': idPenyakit, 'nilai_pakar': nilaiPakar, }), ); return response; } //get all rules penyakit Future> getRulesPenyakit() async { final response = await http.get(Uri.parse(rulesPenyakitUrl)); if (response.statusCode == 200) { final data = jsonDecode(response.body); if (data['data'] == null) { throw Exception('Data rules kosong'); } return data['data']; } else { throw Exception('Gagal mengambil data rules: ${response.statusCode}'); } } // Update Rule penyakit static Future updateRulePenyakit({ required int id, required int idGejala, int? idPenyakit, required double nilaiPakar, }) async { final response = await http.put( Uri.parse('$rulesPenyakitUrl/$id'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'id_gejala': idGejala, 'id_penyakit': idPenyakit, 'nilai_pakar': nilaiPakar, }), ); return response; } // Delete Rule penyakit static Future deleteRulePenyakit(int id) async { final response = await http.delete(Uri.parse('$rulesPenyakitUrl/$id')); return response; } // Create Rule Hama static Future createRuleHama({ required int idGejala, int? idHama, required double nilaiPakar, }) async { try { // Mencetak URL untuk debugging print("URL API: $rulesHamaUrl"); // Kirim request POST ke server final response = await http.post( Uri.parse('$rulesHamaUrl'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'id_gejala': idGejala, 'id_hama': idHama, 'nilai_pakar': nilaiPakar, }), ); // Pengecekan status response if (response.statusCode == 200 || response.statusCode == 201) { // Jika berhasil, kembalikan response return response; } else { // Jika gagal, cetak error dan lempar exception print("Gagal: ${response.statusCode} - ${response.body}"); throw Exception('Gagal menyimpan rule hama. ${response.body}'); } } catch (e) { print('Error: $e'); rethrow; // Rethrow exception agar bisa ditangani di tempat lain } } //get all rules hama Future> getRulesHama() async { final response = await http.get(Uri.parse(rulesHamaUrl)); if (response.statusCode == 200) { final data = jsonDecode(response.body); if (data['data'] == null) { throw Exception('Data rules kosong'); } return data['data']; } else { throw Exception('Gagal mengambil data rules: ${response.statusCode}'); } } // Update Rule hama static Future updateRuleHama({ required int id, required int idGejala, int? idHama, required double nilaiPakar, }) async { final response = await http.put( Uri.parse('$rulesHamaUrl/$id'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'id_gejala': idGejala, 'id_hama': idHama, 'nilai_pakar': nilaiPakar, }), ); return response; } // Delete Rule hama static Future deleteRuleHama(int id) async { final response = await http.delete(Uri.parse('$rulesHamaUrl/$id')); return response; } //get users Future>> getUsers({String? role}) async { try { String url = ApiService.userUrl; if (role != null) { url += '?role=$role'; } final response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { final List responseData = jsonDecode(response.body); // Filter berdasarkan role jika perlu if (role != null) { // Mengambil user dengan role yang sesuai final filteredData = responseData.where((user) => user['role'] == role).toList(); return List>.from(filteredData); } // Jika tidak ada filter role, kembalikan semua data return List>.from(responseData); } else { throw Exception("Gagal mengambil data user: ${response.statusCode}"); } } catch (e) { print("Error getUsers: $e"); throw Exception("Gagal mengambil data user"); } } Future> updateUser({ required int id, String? name, String? email, String? alamat, String? nomorTelepon, String? password, }) async { try { final response = await http.put( Uri.parse('$userUrl/$id'), headers: {"Content-Type": "application/json"}, body: jsonEncode({ if (name != null) 'name': name, if (email != null) 'email': email, if (alamat != null) 'alamat': alamat, if (nomorTelepon != null) 'nomorTelepon': nomorTelepon, if (password != null) 'password': password, }), ); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); return responseData['user']; } else { throw Exception( jsonDecode(response.body)['message'] ?? 'Gagal mengupdate user' ); } } catch (e) { print('Error updating user: $e'); throw Exception('Gagal mengupdate user: $e'); } } Future deleteUser(int id) async { try { final response = await http.delete( Uri.parse('$userUrl/$id'), headers: {"Content-Type": "application/json"}, ); if (response.statusCode == 200) { // Successful deletion print('User deleted successfully'); } else { // Handle error response final errorMessage = jsonDecode(response.body)['message'] ?? 'Gagal menghapus user'; throw Exception(errorMessage); } } catch (e) { print('Error deleting user: $e'); throw Exception('Gagal menghapus user: $e'); } } // Tambahkan fungsi untuk mendapatkan data user berdasarkan ID Future?> getUserById(String userId) async { try { final response = await http.get( Uri.parse('$userUrl/$userId'), // Use userUrl instead of baseUrl headers: { "Content-Type": "application/json", }, ); if (response.statusCode == 200) { return jsonDecode(response.body); // Direct return as backend sends user object } else { print("Error fetching user data: ${response.statusCode}"); return null; } } catch (e) { print("Exception in getUserById: $e"); return null; } } }