last update admin page
|
@ -24,10 +24,12 @@ exports.getHamaById = async (req, res) => {
|
|||
}
|
||||
};
|
||||
|
||||
// 🔹 Fungsi untuk menambahkan hama baru (kode otomatis & kategori default)
|
||||
// Pastikan sudah import 'Hama' model dan multer middleware sebelumnya
|
||||
|
||||
exports.createHama = async (req, res) => {
|
||||
try {
|
||||
const { nama, deskripsi, penanganan } = req.body;
|
||||
const file = req.file;
|
||||
|
||||
// Cek kode terakhir
|
||||
const lastHama = await Hama.findOne({ order: [['id', 'DESC']] });
|
||||
|
@ -37,20 +39,28 @@ exports.createHama = async (req, res) => {
|
|||
newKode = `H${lastNumber.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
// Cek kalau ada file yang diupload
|
||||
let fotoPath = '';
|
||||
if (file) {
|
||||
fotoPath = file.filename;
|
||||
}
|
||||
|
||||
const newHama = await Hama.create({
|
||||
kode: newKode,
|
||||
nama,
|
||||
kategori: 'hama', // Default kategori
|
||||
deskripsi,
|
||||
penanganan,
|
||||
foto: fotoPath, // ⬅️ Masukkan nama file ke database
|
||||
});
|
||||
|
||||
res.status(201).json({ message: 'Hama berhasil ditambahkan', data: newHama });
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: 'Gagal menambahkan hama', error });
|
||||
res.status(500).json({ message: 'Gagal menambahkan hama', error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 🔹 Fungsi untuk mengupdate hama berdasarkan ID
|
||||
exports.updateHama = async (req, res) => {
|
||||
try {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/** @type {import('sequelize-cli').Migration} */
|
||||
module.exports = {
|
||||
async up(queryInterface, Sequelize) {
|
||||
await queryInterface.createTable('hamas', {
|
||||
await queryInterface.createTable('hama', {
|
||||
id: {
|
||||
allowNull: false,
|
||||
autoIncrement: true,
|
||||
|
@ -12,7 +12,6 @@ module.exports = {
|
|||
kode: {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: true
|
||||
|
||||
},
|
||||
nama: {
|
||||
type: Sequelize.STRING,
|
||||
|
@ -28,6 +27,6 @@ module.exports = {
|
|||
});
|
||||
},
|
||||
async down(queryInterface, Sequelize) {
|
||||
await queryInterface.dropTable('hamas');
|
||||
await queryInterface.dropTable('hama');
|
||||
}
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
'use strict';
|
||||
/** @type {import('sequelize-cli').Migration} */
|
||||
module.exports = {
|
||||
async up(queryInterface, Sequelize) {
|
||||
await queryInterface.addColumn('hama', 'foto', {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: true
|
||||
});
|
||||
},
|
||||
|
||||
async down(queryInterface, Sequelize) {
|
||||
await queryInterface.removeColumn('hama', 'foto');
|
||||
}
|
||||
};
|
|
@ -27,6 +27,10 @@ Hama.init(
|
|||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
foto: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
}
|
||||
},
|
||||
{
|
||||
sequelize,
|
||||
|
|
After Width: | Height: | Size: 719 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 707 B |
After Width: | Height: | Size: 871 B |
After Width: | Height: | Size: 952 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 10 KiB |
|
@ -8,51 +8,120 @@ import 'package:frontend/user/login_page.dart';
|
|||
class AdminPage extends StatelessWidget {
|
||||
Future<void> _logout(BuildContext context) async {
|
||||
await ApiService.logoutUser();
|
||||
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => LoginPage()));
|
||||
Navigator.pushReplacement(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => LoginPage()),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Admin Dashboard'),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
appBar: AppBar(title: Text('Admin Dashboard')),
|
||||
drawer: Drawer(
|
||||
child: Container(
|
||||
color: Color(0xFFFFFFFF),
|
||||
child: ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
SizedBox(
|
||||
height: 70,
|
||||
child: DrawerHeader(
|
||||
decoration: BoxDecoration(color: Color(0xFF9DC08D)),
|
||||
child: Text(
|
||||
'Menu Admin',
|
||||
style: TextStyle(color: Colors.white, fontSize: 24),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
ListTile(
|
||||
title: Text('Halaman Hama'),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => HamaPage()),
|
||||
);
|
||||
},
|
||||
child: Text('Halaman Hama'),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
ListTile(
|
||||
title: Text('Halaman Penyakit'),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => PenyakitPage()),
|
||||
);
|
||||
},
|
||||
child: Text('Halaman Penyakit'),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
ListTile(
|
||||
title: Text('Halaman Gejala'),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => GejalaPage()),
|
||||
);
|
||||
},
|
||||
child: Text('Halaman Gejala'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => _logout(context),
|
||||
child: Text('Logout'),
|
||||
ListTile(title: Text('Logout'), onTap: () => _logout(context)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Selamat datang Admin!',
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildCard('Jumlah User', '10'),
|
||||
_buildCard('Jumlah Diagnosa', '25'),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16), // Spasi antar baris
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildCard('Penyakit', '15'),
|
||||
_buildCard('Hama', '15'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCard(String title, String count) {
|
||||
return Card(
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Container(
|
||||
width: 160,
|
||||
height: 160,
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(count, style: TextStyle(fontSize: 20, color: Colors.green)),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/api_services/api_services.dart'; // Pastikan ini di-import ya
|
||||
|
||||
class EditHamaPage extends StatefulWidget {
|
||||
final int idHama;
|
||||
final String namaAwal;
|
||||
final String deskripsiAwal;
|
||||
final String penangananAwal;
|
||||
final VoidCallback onHamaUpdated;
|
||||
|
||||
const EditHamaPage({
|
||||
Key? key,
|
||||
required this.idHama,
|
||||
required this.namaAwal,
|
||||
required this.deskripsiAwal,
|
||||
required this.penangananAwal,
|
||||
required this.onHamaUpdated,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_EditHamaPageState createState() => _EditHamaPageState();
|
||||
}
|
||||
|
||||
class _EditHamaPageState extends State<EditHamaPage> {
|
||||
final TextEditingController _namaController = TextEditingController();
|
||||
final TextEditingController _deskripsiController = TextEditingController();
|
||||
final TextEditingController _penangananController = TextEditingController();
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_namaController.text = widget.namaAwal;
|
||||
_deskripsiController.text = widget.deskripsiAwal;
|
||||
_penangananController.text = widget.penangananAwal;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_namaController.dispose();
|
||||
_deskripsiController.dispose();
|
||||
_penangananController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _updateHama() async {
|
||||
try {
|
||||
await apiService.updateHama(
|
||||
widget.idHama,
|
||||
_namaController.text,
|
||||
_deskripsiController.text,
|
||||
_penangananController.text,
|
||||
);
|
||||
widget.onHamaUpdated();
|
||||
Navigator.pop(context);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Data hama berhasil diperbarui')),
|
||||
);
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Gagal memperbarui data: $e')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Edit Data Hama'),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Center(
|
||||
child: Card(
|
||||
elevation: 5,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: _namaController,
|
||||
decoration: InputDecoration(labelText: 'Nama Hama'),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _deskripsiController,
|
||||
decoration: InputDecoration(labelText: 'Deskripsi'),
|
||||
maxLines: 3,
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _penangananController,
|
||||
decoration: InputDecoration(labelText: 'Penanganan'),
|
||||
maxLines: 3,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: _updateHama,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green[300],
|
||||
),
|
||||
child: Text(
|
||||
'Simpan Perubahan',
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/api_services/api_services.dart'; // Pastikan ini di-import ya
|
||||
|
||||
class EditPenyakitPage extends StatefulWidget {
|
||||
final int idPenyakit;
|
||||
final String namaAwal;
|
||||
final String deskripsiAwal;
|
||||
final String penangananAwal;
|
||||
final VoidCallback onPenyakitUpdated;
|
||||
|
||||
const EditPenyakitPage({
|
||||
Key? key,
|
||||
required this.idPenyakit,
|
||||
required this.namaAwal,
|
||||
required this.deskripsiAwal,
|
||||
required this.penangananAwal,
|
||||
required this.onPenyakitUpdated,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_EditPenyakitPageState createState() => _EditPenyakitPageState();
|
||||
}
|
||||
|
||||
class _EditPenyakitPageState extends State<EditPenyakitPage> {
|
||||
final TextEditingController _namaController = TextEditingController();
|
||||
final TextEditingController _deskripsiController = TextEditingController();
|
||||
final TextEditingController _penangananController = TextEditingController();
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_namaController.text = widget.namaAwal;
|
||||
_deskripsiController.text = widget.deskripsiAwal;
|
||||
_penangananController.text = widget.penangananAwal;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_namaController.dispose();
|
||||
_deskripsiController.dispose();
|
||||
_penangananController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _updatePenyakit() async {
|
||||
try {
|
||||
await apiService.updatePenyakit(
|
||||
widget.idPenyakit,
|
||||
_namaController.text,
|
||||
_deskripsiController.text,
|
||||
_penangananController.text,
|
||||
);
|
||||
widget.onPenyakitUpdated();
|
||||
Navigator.pop(context);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Data penyakit berhasil diperbarui')),
|
||||
);
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Gagal memperbarui data: $e')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Edit Data Penyakit'),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Center(
|
||||
child: Card(
|
||||
elevation: 5,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: _namaController,
|
||||
decoration: InputDecoration(labelText: 'Nama Penyakit'),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _deskripsiController,
|
||||
decoration: InputDecoration(labelText: 'Deskripsi'),
|
||||
maxLines: 3,
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _penangananController,
|
||||
decoration: InputDecoration(labelText: 'Penanganan'),
|
||||
maxLines: 3,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: _updatePenyakit,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green[300],
|
||||
),
|
||||
child: Text(
|
||||
'Simpan Perubahan',
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -69,6 +69,53 @@ class _GejalaPageState extends State<GejalaPage> {
|
|||
);
|
||||
}
|
||||
|
||||
void showEditDialog(BuildContext context, Map<String, dynamic> gejala) {
|
||||
final TextEditingController editNamaController = TextEditingController(text: gejala['nama'] ?? '');
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
'Edit Hama',
|
||||
),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: editNamaController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Nama',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text('Batal'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
await apiService.updateGejala(
|
||||
gejala['id'],
|
||||
editNamaController.text
|
||||
);
|
||||
fetchGejala();
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
print("Error updating gejala: $e");
|
||||
}
|
||||
},
|
||||
child: Text('Simpan', style: TextStyle(color: Colors.black)),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// 🔹 Hapus gejala dari API
|
||||
void _hapusGejala(int id) async {
|
||||
try {
|
||||
|
@ -108,10 +155,23 @@ class _GejalaPageState extends State<GejalaPage> {
|
|||
}
|
||||
|
||||
|
||||
|
||||
//pagination
|
||||
int currentPage = 0;
|
||||
int rowsPerPage = 10;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int start = currentPage * rowsPerPage;
|
||||
int end = (start + rowsPerPage < gejalaList.length)
|
||||
? start + rowsPerPage
|
||||
: gejalaList.length;
|
||||
List currentPageData = gejalaList.sublist(start, end);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('Halaman Gejala')),
|
||||
appBar: AppBar(
|
||||
title: Text('Halaman Gejala'),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
SizedBox(height: 20),
|
||||
|
@ -122,39 +182,90 @@ class _GejalaPageState extends State<GejalaPage> {
|
|||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: _tambahGejala,
|
||||
child: Text('Tambah Gejala'),
|
||||
child: Text(
|
||||
'Tambah Gejala',
|
||||
style: TextStyle(color: Colors.green[200]),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.9,
|
||||
child: DataTable(
|
||||
columnSpacing: 20,
|
||||
headingRowColor: MaterialStateColor.resolveWith((states) => Colors.grey[300]!),
|
||||
headingRowColor: MaterialStateColor.resolveWith(
|
||||
(states) => const Color(0xFF9DC08D),
|
||||
),
|
||||
columns: [
|
||||
DataColumn(label: SizedBox(width: 50, child: Text('No'))),
|
||||
DataColumn(label: SizedBox(width: 35, child: Text('No'))),
|
||||
DataColumn(label: SizedBox(width: 80, child: Text('Kode'))),
|
||||
DataColumn(label: SizedBox(width: 150, child: Text('Nama'))),
|
||||
DataColumn(label: SizedBox(width: 80, child: Text('Aksi'))),
|
||||
],
|
||||
rows: gejalaList.map(
|
||||
(gejala) => DataRow(cells: [
|
||||
DataCell(Text((gejalaList.indexOf(gejala) + 1).toString())), // Nomor
|
||||
DataCell(Text(gejala['kode'])), // Kode Gejala
|
||||
DataCell(Text(gejala['nama'])), // Nama Gejala
|
||||
rows: [
|
||||
...currentPageData.map(
|
||||
(gejala) => DataRow(
|
||||
cells: [
|
||||
DataCell(Text((gejalaList.indexOf(gejala) + 1).toString())),
|
||||
DataCell(Text(gejala['kode'] ?? '-')),
|
||||
DataCell(Text(gejala['nama'] ?? '-')),
|
||||
DataCell(
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.edit, color: Color(0xFF9DC08D)),
|
||||
onPressed: () => showEditDialog(context, gejala),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.delete, color: Colors.red),
|
||||
onPressed: () => _konfirmasiHapus(gejala['id']), // Hapus data
|
||||
onPressed: () => _konfirmasiHapus(gejala['id']),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
]),
|
||||
).toList(),
|
||||
],
|
||||
),
|
||||
),
|
||||
DataRow(
|
||||
cells: [
|
||||
DataCell(Container()),
|
||||
DataCell(Container()),
|
||||
DataCell(
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.chevron_left),
|
||||
onPressed: currentPage > 0
|
||||
? () => setState(() => currentPage--)
|
||||
: null,
|
||||
),
|
||||
Text(' ${currentPage + 1}'),
|
||||
IconButton(
|
||||
icon: Icon(Icons.chevron_right),
|
||||
onPressed:
|
||||
(currentPage + 1) * rowsPerPage < gejalaList.length
|
||||
? () => setState(() => currentPage++)
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(Container()),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -163,4 +274,5 @@ class _GejalaPageState extends State<GejalaPage> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/api_services/api_services.dart';
|
||||
|
||||
import 'tambah_hama_page.dart';
|
||||
import 'edit_hama_page.dart';
|
||||
|
||||
class HamaPage extends StatefulWidget {
|
||||
@override
|
||||
|
@ -66,71 +67,140 @@ class _HamaPageState extends State<HamaPage> {
|
|||
);
|
||||
}
|
||||
|
||||
void _tambahHama() {
|
||||
TextEditingController namaController = TextEditingController();
|
||||
TextEditingController penangananController = TextEditingController();
|
||||
TextEditingController deskripsiController = TextEditingController();
|
||||
// void _tambahHama() {
|
||||
// TextEditingController namaController = TextEditingController();
|
||||
// TextEditingController penangananController = TextEditingController();
|
||||
// TextEditingController deskripsiController = TextEditingController();
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text('Tambah Hama Baru'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: namaController,
|
||||
decoration: InputDecoration(labelText: 'Nama'),
|
||||
),
|
||||
TextField(
|
||||
controller: deskripsiController,
|
||||
decoration: InputDecoration(labelText: 'Deskripsi'),
|
||||
),
|
||||
TextField(
|
||||
controller: penangananController,
|
||||
decoration: InputDecoration(labelText: 'Penanganan'),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text('Batal'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (namaController.text.isNotEmpty &&
|
||||
deskripsiController.text.isNotEmpty &&
|
||||
penangananController.text.isNotEmpty) {
|
||||
try {
|
||||
await apiService.createHama(
|
||||
namaController.text,
|
||||
deskripsiController.text,
|
||||
penangananController.text,
|
||||
);
|
||||
_fetchHama();
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
print("Error adding hama: $e");
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Text('Simpan'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
).then((_) {
|
||||
namaController.dispose();
|
||||
deskripsiController.dispose();
|
||||
penangananController.dispose();
|
||||
});
|
||||
}
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return AlertDialog(
|
||||
// title: Text('Tambah Hama Baru'),
|
||||
// content: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// TextField(
|
||||
// controller: namaController,
|
||||
// decoration: InputDecoration(labelText: 'Nama'),
|
||||
// ),
|
||||
// TextField(
|
||||
// controller: deskripsiController,
|
||||
// decoration: InputDecoration(labelText: 'Deskripsi'),
|
||||
// ),
|
||||
// TextField(
|
||||
// controller: penangananController,
|
||||
// decoration: InputDecoration(labelText: 'Penanganan'),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// actions: [
|
||||
// TextButton(
|
||||
// onPressed: () => Navigator.pop(context),
|
||||
// child: Text('Batal', style: TextStyle(color: Colors.black)),
|
||||
// ),
|
||||
// ElevatedButton(
|
||||
// onPressed: () async {
|
||||
// if (namaController.text.isNotEmpty &&
|
||||
// deskripsiController.text.isNotEmpty &&
|
||||
// penangananController.text.isNotEmpty) {
|
||||
// try {
|
||||
// await apiService.createHama(
|
||||
// namaController.text,
|
||||
// deskripsiController.text,
|
||||
// penangananController.text,
|
||||
// );
|
||||
// _fetchHama();
|
||||
// Navigator.pop(context);
|
||||
// } catch (e) {
|
||||
// print("Error adding hama: $e");
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// child: Text('Simpan', style: TextStyle(color: Colors.black)),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// },
|
||||
// ).then((_) {
|
||||
// namaController.dispose();
|
||||
// deskripsiController.dispose();
|
||||
// penangananController.dispose();
|
||||
// });
|
||||
// }
|
||||
|
||||
// void showEditDialog(BuildContext context, Map<String, dynamic> hama) {
|
||||
// final TextEditingController editNamaController = TextEditingController(
|
||||
// text: hama['nama'] ?? '',
|
||||
// );
|
||||
// final TextEditingController editDeskripsiController = TextEditingController(
|
||||
// text: hama['deskripsi'] ?? '',
|
||||
// );
|
||||
// final TextEditingController editPenangananController =
|
||||
// TextEditingController(text: hama['penanganan'] ?? '');
|
||||
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return AlertDialog(
|
||||
// title: Text('Edit Hama'),
|
||||
// content: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// TextField(
|
||||
// controller: editNamaController,
|
||||
// decoration: InputDecoration(labelText: 'Nama'),
|
||||
// ),
|
||||
// TextField(
|
||||
// controller: editDeskripsiController,
|
||||
// decoration: InputDecoration(labelText: 'Deskripsi'),
|
||||
// ),
|
||||
// TextField(
|
||||
// controller: editPenangananController,
|
||||
// decoration: InputDecoration(labelText: 'Penanganan'),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// actions: [
|
||||
// TextButton(
|
||||
// onPressed: () => Navigator.pop(context),
|
||||
// child: Text('Batal'),
|
||||
// ),
|
||||
// ElevatedButton(
|
||||
// onPressed: () async {
|
||||
// try {
|
||||
// await apiService.updateHama(
|
||||
// hama['id'],
|
||||
// editNamaController.text,
|
||||
// editDeskripsiController.text,
|
||||
// editPenangananController.text,
|
||||
// );
|
||||
// _fetchHama();
|
||||
// Navigator.pop(context);
|
||||
// } catch (e) {
|
||||
// print("Error updating hama: $e");
|
||||
// }
|
||||
// },
|
||||
// child: Text('Simpan', style: TextStyle(color: Colors.black)),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
|
||||
//pagination
|
||||
int currentPage = 0;
|
||||
int rowsPerPage = 10;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int start = currentPage * rowsPerPage;
|
||||
int end =
|
||||
(start + rowsPerPage < hamaList.length)
|
||||
? start + rowsPerPage
|
||||
: hamaList.length;
|
||||
List currentPageData = hamaList.sublist(start, end);
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('Halaman Hama')),
|
||||
body: Column(
|
||||
|
@ -142,45 +212,147 @@ class _HamaPageState extends State<HamaPage> {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: _tambahHama, // Fungsi untuk menambah data hama
|
||||
child: Text('Tambah Hama'),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => TambahHamaPage(
|
||||
onHamaAdded:
|
||||
_fetchHama, // Panggil fungsi refresh setelah tambah
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'Tambah Hama',
|
||||
style: TextStyle(color: Colors.green[200]),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.9,
|
||||
child: DataTable(
|
||||
columnSpacing: 20,
|
||||
headingRowColor:
|
||||
MaterialStateColor.resolveWith((states) => Colors.grey[300]!),
|
||||
headingRowColor: MaterialStateColor.resolveWith(
|
||||
(states) => const Color(0xFF9DC08D),
|
||||
),
|
||||
columns: [
|
||||
DataColumn(label: SizedBox(width: 35, child: Text('No'))),
|
||||
DataColumn(label: SizedBox(width: 50, child: Text('Kode'))),
|
||||
DataColumn(label: SizedBox(width: 100, child: Text('Nama'))),
|
||||
DataColumn(label: SizedBox(width: 100, child: Text('Deskripsi'))),
|
||||
DataColumn(label: SizedBox(width: 100, child: Text('Penanganan'))),
|
||||
DataColumn(label: SizedBox(width: 50, child: Text('Aksi'))),
|
||||
DataColumn(
|
||||
label: SizedBox(width: 50, child: Text('Kode')),
|
||||
),
|
||||
DataColumn(
|
||||
label: SizedBox(width: 100, child: Text('Nama')),
|
||||
),
|
||||
DataColumn(
|
||||
label: SizedBox(width: 100, child: Text('Deskripsi')),
|
||||
),
|
||||
DataColumn(
|
||||
label: SizedBox(width: 100, child: Text('Penanganan')),
|
||||
),
|
||||
DataColumn(
|
||||
label: SizedBox(width: 50, child: Text('Aksi')),
|
||||
),
|
||||
],
|
||||
rows: hamaList.map(
|
||||
(hama) => DataRow(cells: [
|
||||
DataCell(Text((hamaList.indexOf(hama) + 1).toString())), // Nomor
|
||||
DataCell(Text(hama['kode'] ?? '-')), // Kode Hama
|
||||
DataCell(Text(hama['nama'] ?? '-')), // Nama Hama
|
||||
DataCell(Text(hama['deskripsi'] ?? '-')), // Deskripsi
|
||||
DataCell(Text(hama['penanganan'] ?? '-')), // Penanganan
|
||||
rows: [
|
||||
...currentPageData.map(
|
||||
(hama) => DataRow(
|
||||
cells: [
|
||||
DataCell(
|
||||
Text((hamaList.indexOf(hama) + 1).toString()),
|
||||
),
|
||||
DataCell(Text(hama['kode'] ?? '-')),
|
||||
DataCell(Text(hama['nama'] ?? '-')),
|
||||
DataCell(Text(hama['deskripsi'] ?? '-')),
|
||||
DataCell(Text(hama['penanganan'] ?? '-')),
|
||||
DataCell(
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.edit,
|
||||
color: Color(0xFF9DC08D),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => EditHamaPage(
|
||||
idHama:
|
||||
hama['id'], // pastikan 'hama' adalah Map dari API kamu
|
||||
namaAwal: hama['nama'] ?? '',
|
||||
deskripsiAwal:
|
||||
hama['deskripsi'] ?? '',
|
||||
penangananAwal:
|
||||
hama['penanganan'] ?? '',
|
||||
onHamaUpdated:
|
||||
_fetchHama, // fungsi untuk refresh list setelah update
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
IconButton(
|
||||
icon: Icon(Icons.delete, color: Colors.red),
|
||||
onPressed: () => _konfirmasiHapus(hama['id']), // Hapus data
|
||||
onPressed:
|
||||
() => _konfirmasiHapus(hama['id']),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
]),
|
||||
).toList(),
|
||||
],
|
||||
),
|
||||
),
|
||||
DataRow(
|
||||
cells: [
|
||||
DataCell(Container()),
|
||||
DataCell(Container()),
|
||||
DataCell(
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.chevron_left),
|
||||
onPressed:
|
||||
currentPage > 0
|
||||
? () =>
|
||||
setState(() => currentPage--)
|
||||
: null,
|
||||
),
|
||||
Text(' ${currentPage + 1}'),
|
||||
IconButton(
|
||||
icon: Icon(Icons.chevron_right),
|
||||
onPressed:
|
||||
(currentPage + 1) * rowsPerPage <
|
||||
hamaList.length
|
||||
? () =>
|
||||
setState(() => currentPage++)
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(Container()),
|
||||
DataCell(Container()),
|
||||
DataCell(Container()),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -189,5 +361,4 @@ class _HamaPageState extends State<HamaPage> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/admin/edit_penyakit_page.dart';
|
||||
import 'package:frontend/api_services/api_services.dart';
|
||||
import 'tambah_penyakit_page.dart';
|
||||
import 'edit_penyakit_page.dart';
|
||||
|
||||
class PenyakitPage extends StatefulWidget {
|
||||
@override
|
||||
|
@ -65,70 +68,146 @@ class _PenyakitPageState extends State<PenyakitPage> {
|
|||
);
|
||||
}
|
||||
|
||||
void _tambahPenyakit() {
|
||||
TextEditingController namaController = TextEditingController();
|
||||
TextEditingController penangananController = TextEditingController();
|
||||
TextEditingController deskripsiController = TextEditingController();
|
||||
// void _tambahPenyakit() {
|
||||
// TextEditingController namaController = TextEditingController();
|
||||
// TextEditingController penangananController = TextEditingController();
|
||||
// TextEditingController deskripsiController = TextEditingController();
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text('Tambah Penyakit Baru'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: namaController,
|
||||
decoration: InputDecoration(labelText: 'Nama'),
|
||||
),
|
||||
TextField(
|
||||
controller: deskripsiController,
|
||||
decoration: InputDecoration(labelText: 'Deskripsi'),
|
||||
),
|
||||
TextField(
|
||||
controller: penangananController,
|
||||
decoration: InputDecoration(labelText: 'Penanganan'),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text('Batal'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (namaController.text.isNotEmpty &&
|
||||
deskripsiController.text.isNotEmpty &&
|
||||
penangananController.text.isNotEmpty) {
|
||||
try {
|
||||
await apiService.createPenyakit(
|
||||
namaController.text,
|
||||
deskripsiController.text,
|
||||
penangananController.text,
|
||||
);
|
||||
_fetchPenyakit();
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
print("Error adding penyakit: $e");
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Text('Simpan'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
).then((_) {
|
||||
namaController.dispose();
|
||||
deskripsiController.dispose();
|
||||
penangananController.dispose();
|
||||
});
|
||||
}
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return AlertDialog(
|
||||
// title: Text('Tambah Penyakit Baru'),
|
||||
// content: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// TextField(
|
||||
// controller: namaController,
|
||||
// decoration: InputDecoration(labelText: 'Nama'),
|
||||
// ),
|
||||
// TextField(
|
||||
// controller: deskripsiController,
|
||||
// decoration: InputDecoration(labelText: 'Deskripsi'),
|
||||
// ),
|
||||
// TextField(
|
||||
// controller: penangananController,
|
||||
// decoration: InputDecoration(labelText: 'Penanganan'),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// actions: [
|
||||
// TextButton(
|
||||
// onPressed: () => Navigator.pop(context),
|
||||
// child: Text('Batal'),
|
||||
// ),
|
||||
// ElevatedButton(
|
||||
// onPressed: () async {
|
||||
// if (namaController.text.isNotEmpty &&
|
||||
// deskripsiController.text.isNotEmpty &&
|
||||
// penangananController.text.isNotEmpty) {
|
||||
// try {
|
||||
// await apiService.createPenyakit(
|
||||
// namaController.text,
|
||||
// deskripsiController.text,
|
||||
// penangananController.text,
|
||||
// );
|
||||
// _fetchPenyakit();
|
||||
// Navigator.pop(context);
|
||||
// } catch (e) {
|
||||
// print("Error adding penyakit: $e");
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// child: Text('Simpan'),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// },
|
||||
// ).then((_) {
|
||||
// namaController.dispose();
|
||||
// deskripsiController.dispose();
|
||||
// penangananController.dispose();
|
||||
// });
|
||||
// }
|
||||
|
||||
// void showEditDialog(BuildContext context, Map<String, dynamic> penyakit) {
|
||||
// final TextEditingController editNamaController = TextEditingController(text: penyakit['nama'] ?? '');
|
||||
// final TextEditingController editDeskripsiController = TextEditingController(text: penyakit['deskripsi'] ?? '');
|
||||
// final TextEditingController editPenangananController = TextEditingController(text: penyakit['penanganan'] ?? '');
|
||||
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return AlertDialog(
|
||||
// title: Text(
|
||||
// 'Edit Penyakit',
|
||||
// ),
|
||||
// content: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// TextField(
|
||||
// controller: editNamaController,
|
||||
// decoration: InputDecoration(
|
||||
// labelText: 'Nama',
|
||||
// ),
|
||||
// ),
|
||||
// TextField(
|
||||
// controller: editDeskripsiController,
|
||||
// decoration: InputDecoration(
|
||||
// labelText: 'Deskripsi',
|
||||
// ),
|
||||
// ),
|
||||
// TextField(
|
||||
// controller: editPenangananController,
|
||||
// decoration: InputDecoration(
|
||||
// labelText: 'Penanganan',
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// actions: [
|
||||
// TextButton(
|
||||
// onPressed: () => Navigator.pop(context),
|
||||
// child: Text(
|
||||
// 'Batal',
|
||||
// style: TextStyle(color: Colors.black),
|
||||
// ),
|
||||
// ),
|
||||
// ElevatedButton(
|
||||
// onPressed: () async {
|
||||
// try {
|
||||
// await apiService.updatePenyakit(
|
||||
// penyakit['id'],
|
||||
// editNamaController.text,
|
||||
// editDeskripsiController.text,
|
||||
// editPenangananController.text,
|
||||
// );
|
||||
// _fetchPenyakit();
|
||||
// Navigator.pop(context);
|
||||
// } catch (e) {
|
||||
// print("Error updating penyakit: $e");
|
||||
// }
|
||||
// },
|
||||
// child: Text('Simpan', style: TextStyle(color: Colors.black)),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
|
||||
//pagination
|
||||
int currentPage = 0;
|
||||
int rowsPerPage = 10;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int start = currentPage * rowsPerPage;
|
||||
int end =
|
||||
(start + rowsPerPage < penyakitList.length)
|
||||
? start + rowsPerPage
|
||||
: penyakitList.length;
|
||||
List currentPageData = penyakitList.sublist(start, end);
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('Halaman Penyakit')),
|
||||
body: Column(
|
||||
|
@ -140,45 +219,146 @@ class _PenyakitPageState extends State<PenyakitPage> {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: _tambahPenyakit, // Fungsi untuk menambah data penyakit
|
||||
child: Text('Tambah Penyakit'),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => TambahPenyakitPage(
|
||||
onPenyakitAdded:
|
||||
_fetchPenyakit, // Panggil fungsi refresh setelah tambah
|
||||
),
|
||||
),
|
||||
);
|
||||
}, // Fungsi untuk menambah data penyakit
|
||||
child: Text(
|
||||
'Tambah Penyakit',
|
||||
style: TextStyle(color: Colors.green[200]),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.95,
|
||||
child: DataTable(
|
||||
columnSpacing: 5,
|
||||
headingRowColor:
|
||||
MaterialStateColor.resolveWith((states) => Colors.grey[300]!),
|
||||
columnSpacing: 20,
|
||||
headingRowColor: MaterialStateColor.resolveWith(
|
||||
(states) => const Color(0xFF9DC08D),
|
||||
),
|
||||
columns: [
|
||||
DataColumn(label: SizedBox(width: 35, child: Text('No'))),
|
||||
DataColumn(label: SizedBox(width: 50, child: Text('Kode'))),
|
||||
DataColumn(label: SizedBox(width: 100, child: Text('Nama'))),
|
||||
DataColumn(label: SizedBox(width: 100, child: Text('Deskripsi'))),
|
||||
DataColumn(label: SizedBox(width: 100, child: Text('Penanganan'))),
|
||||
DataColumn(label: SizedBox(width: 50, child: Text('Aksi'))),
|
||||
DataColumn(
|
||||
label: SizedBox(width: 50, child: Text('Kode')),
|
||||
),
|
||||
DataColumn(
|
||||
label: SizedBox(width: 100, child: Text('Nama')),
|
||||
),
|
||||
DataColumn(
|
||||
label: SizedBox(width: 100, child: Text('Deskripsi')),
|
||||
),
|
||||
DataColumn(
|
||||
label: SizedBox(width: 100, child: Text('Penanganan')),
|
||||
),
|
||||
DataColumn(
|
||||
label: SizedBox(width: 50, child: Text('Aksi')),
|
||||
),
|
||||
],
|
||||
rows: penyakitList.map(
|
||||
(penyakit) => DataRow(cells: [
|
||||
DataCell(Text((penyakitList.indexOf(penyakit) + 1).toString())), // Nomor
|
||||
DataCell(Text(penyakit['kode'] ?? '-')), // Kode Penyakit
|
||||
DataCell(Text(penyakit['nama'] ?? '-')), // Nama Penyakit
|
||||
DataCell(Text(penyakit['deskripsi'] ?? '-')), // Deskripsi
|
||||
DataCell(Text(penyakit['penanganan'] ?? '-')), // Penanganan
|
||||
rows: [
|
||||
...currentPageData.map(
|
||||
(penyakit) => DataRow(
|
||||
cells: [
|
||||
DataCell(
|
||||
Text((penyakitList.indexOf(penyakit) + 1).toString()),
|
||||
),
|
||||
DataCell(Text(penyakit['kode'] ?? '-')),
|
||||
DataCell(Text(penyakit['nama'] ?? '-')),
|
||||
DataCell(Text(penyakit['deskripsi'] ?? '-')),
|
||||
DataCell(Text(penyakit['penanganan'] ?? '-')),
|
||||
DataCell(
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.edit,
|
||||
color: Color(0xFF9DC08D),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => EditPenyakitPage(
|
||||
idPenyakit:
|
||||
penyakit['id'], // pastikan 'hama' adalah Map dari API kamu
|
||||
namaAwal: penyakit['nama'] ?? '',
|
||||
deskripsiAwal:
|
||||
penyakit['deskripsi'] ?? '',
|
||||
penangananAwal:
|
||||
penyakit['penanganan'] ?? '',
|
||||
onPenyakitUpdated:
|
||||
_fetchPenyakit, // fungsi untuk refresh list setelah update
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.delete, color: Colors.red),
|
||||
onPressed: () => _konfirmasiHapus(penyakit['id']), // Hapus data
|
||||
onPressed:
|
||||
() => _konfirmasiHapus(penyakit['id']),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
]),
|
||||
).toList(),
|
||||
],
|
||||
),
|
||||
),
|
||||
DataRow(
|
||||
cells: [
|
||||
DataCell(Container()),
|
||||
DataCell(Container()),
|
||||
DataCell(
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.chevron_left),
|
||||
onPressed:
|
||||
currentPage > 0
|
||||
? () =>
|
||||
setState(() => currentPage--)
|
||||
: null,
|
||||
),
|
||||
Text(' ${currentPage + 1}'),
|
||||
IconButton(
|
||||
icon: Icon(Icons.chevron_right),
|
||||
onPressed:
|
||||
(currentPage + 1) * rowsPerPage <
|
||||
penyakitList.length
|
||||
? () =>
|
||||
setState(() => currentPage++)
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(Container()),
|
||||
DataCell(Container()),
|
||||
DataCell(Container()),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/api_services/api_services.dart';
|
||||
|
||||
class TambahHamaPage extends StatefulWidget {
|
||||
final VoidCallback onHamaAdded;
|
||||
|
||||
TambahHamaPage({required this.onHamaAdded});
|
||||
|
||||
@override
|
||||
_TambahHamaPageState createState() => _TambahHamaPageState();
|
||||
}
|
||||
|
||||
class _TambahHamaPageState extends State<TambahHamaPage> {
|
||||
final TextEditingController namaController = TextEditingController();
|
||||
final TextEditingController deskripsiController = TextEditingController();
|
||||
final TextEditingController penangananController = TextEditingController();
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
namaController.dispose();
|
||||
deskripsiController.dispose();
|
||||
penangananController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _simpanHama() async {
|
||||
if (namaController.text.isNotEmpty &&
|
||||
deskripsiController.text.isNotEmpty &&
|
||||
penangananController.text.isNotEmpty) {
|
||||
try {
|
||||
await apiService.createHama(
|
||||
namaController.text,
|
||||
deskripsiController.text,
|
||||
penangananController.text,
|
||||
);
|
||||
widget.onHamaAdded();
|
||||
Navigator.pop(context);
|
||||
_showDialog('Berhasil', 'Data hama berhasil ditambahkan.');
|
||||
} catch (e) {
|
||||
_showDialog('Gagal', 'Gagal menambahkan data hama.');
|
||||
print("Error adding hama: $e");
|
||||
}
|
||||
} else {
|
||||
_showDialog('Error', 'Semua field harus diisi.');
|
||||
}
|
||||
}
|
||||
|
||||
void _showDialog(String title, String message) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(title),
|
||||
content: Text(message),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text('OK'),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Tambah Hama Baru'),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 30.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Card(
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Container(
|
||||
width: 320, // atur lebar card box
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
TextField(
|
||||
controller: namaController,
|
||||
decoration: InputDecoration(labelText: 'Nama Hama'),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
TextField(
|
||||
controller: deskripsiController,
|
||||
decoration: InputDecoration(labelText: 'Deskripsi Hama'),
|
||||
maxLines: 3, // Biar lebih panjang untuk deskripsi
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
TextField(
|
||||
controller: penangananController,
|
||||
decoration: InputDecoration(labelText: 'Penanganan Hama'),
|
||||
maxLines: 3,
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 30), // jarak antara card dan tombol
|
||||
ElevatedButton(
|
||||
onPressed: _simpanHama,
|
||||
child: Text('Simpan Data'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green[300],
|
||||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15),
|
||||
textStyle: TextStyle(fontSize: 16, color: Colors.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/api_services/api_services.dart';
|
||||
|
||||
class TambahPenyakitPage extends StatefulWidget {
|
||||
final VoidCallback onPenyakitAdded;
|
||||
|
||||
TambahPenyakitPage({required this.onPenyakitAdded});
|
||||
|
||||
@override
|
||||
_TambahPenyakitPageState createState() => _TambahPenyakitPageState();
|
||||
}
|
||||
|
||||
class _TambahPenyakitPageState extends State<TambahPenyakitPage> {
|
||||
final TextEditingController namaController = TextEditingController();
|
||||
final TextEditingController deskripsiController = TextEditingController();
|
||||
final TextEditingController penangananController = TextEditingController();
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
namaController.dispose();
|
||||
deskripsiController.dispose();
|
||||
penangananController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _simpanPenyakit() async {
|
||||
if (namaController.text.isNotEmpty &&
|
||||
deskripsiController.text.isNotEmpty &&
|
||||
penangananController.text.isNotEmpty) {
|
||||
try {
|
||||
await apiService.createPenyakit(
|
||||
namaController.text,
|
||||
deskripsiController.text,
|
||||
penangananController.text,
|
||||
);
|
||||
widget.onPenyakitAdded();
|
||||
Navigator.pop(context);
|
||||
_showDialog('Berhasil', 'Data penyakit berhasil ditambahkan.');
|
||||
} catch (e) {
|
||||
_showDialog('Gagal', 'Gagal menambahkan data penyakit.');
|
||||
print("Error adding penyakit: $e");
|
||||
}
|
||||
} else {
|
||||
_showDialog('Error', 'Semua field harus diisi.');
|
||||
}
|
||||
}
|
||||
|
||||
void _showDialog(String title, String message) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(title),
|
||||
content: Text(message),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text('OK'),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Tambah Penyakit Baru'),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 30.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Card(
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Container(
|
||||
width: 320, // atur lebar card box
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
TextField(
|
||||
controller: namaController,
|
||||
decoration: InputDecoration(labelText: 'Nama Penyakit'),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
TextField(
|
||||
controller: deskripsiController,
|
||||
decoration: InputDecoration(labelText: 'Deskripsi Penyakit'),
|
||||
maxLines: 3, // Biar lebih panjang untuk deskripsi
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
TextField(
|
||||
controller: penangananController,
|
||||
decoration: InputDecoration(labelText: 'Penanganan Penyakit'),
|
||||
maxLines: 3,
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 30), // jarak antara card dan tombol
|
||||
ElevatedButton(
|
||||
onPressed: _simpanPenyakit,
|
||||
child: Text('Simpan Data'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green[300],
|
||||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15),
|
||||
textStyle: TextStyle(fontSize: 16, color: Colors.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -281,5 +281,51 @@ class ApiService {
|
|||
throw Exception('Gagal menghapus penyakit');
|
||||
}
|
||||
}
|
||||
|
||||
//registrasi
|
||||
Future<void> 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 lupa password
|
||||
Future<void> forgotPassword({
|
||||
required String email,
|
||||
required String newPassword,
|
||||
}) async {
|
||||
final response = await http.post(
|
||||
Uri.parse('$baseUrl/forgot-password'),
|
||||
headers: {"Content-Type": "application/json"},
|
||||
body: jsonEncode({
|
||||
'email': email,
|
||||
'password': newPassword, // Kirim password baru
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception(jsonDecode(response.body)['message'] ?? 'Gagal memperbarui password');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'hama_page.dart';
|
||||
import 'penyakit_page.dart';
|
||||
|
||||
class BasisPengetahuanPage extends StatelessWidget {
|
||||
@override
|
||||
|
@ -31,7 +33,12 @@ class BasisPengetahuanPage extends StatelessWidget {
|
|||
// Button pertama
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// Aksi untuk button pertama
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => HamaPage(),
|
||||
), // Perbaikan di sini
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
|
@ -67,7 +74,12 @@ class BasisPengetahuanPage extends StatelessWidget {
|
|||
// Button kedua
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// Aksi untuk button kedua
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => PenyakitPage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class DetailHamaPage extends StatelessWidget {
|
||||
final Map<String, String> detailRiwayat;
|
||||
|
||||
const DetailHamaPage({required this.detailRiwayat});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFF9DC08D),
|
||||
appBar: AppBar(
|
||||
backgroundColor: Color(0xFF9DC08D),
|
||||
title: Text(
|
||||
"Detail Hama",
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back, color: Colors.white),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
if (detailRiwayat["gambar"] != null && detailRiwayat["gambar"]!.isNotEmpty)
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Image.asset(
|
||||
detailRiwayat["gambar"]!,
|
||||
height: 200,
|
||||
width: 200, // Biar gambar full lebar
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
|
||||
// Card Nama Hama
|
||||
SizedBox(
|
||||
width: double.infinity, // Bikin card full lebar
|
||||
child: Card(
|
||||
elevation: 6,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Nama Hama:",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
detailRiwayat["nama hama"] ?? "Nama hama tidak tersedia",
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
|
||||
// Card Deskripsi + Penanganan
|
||||
SizedBox(
|
||||
width: double.infinity, // Bikin card full lebar
|
||||
child: Card(
|
||||
elevation: 6,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Deskripsi:",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
detailRiwayat["deskripsi"] ?? "Deskripsi tidak tersedia",
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
"Penanganan:",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
detailRiwayat["penanganan"] ?? "Penanganan tidak tersedia",
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class DetailPenyakitPage extends StatelessWidget {
|
||||
final Map<String, String> detailPenyakit;
|
||||
|
||||
const DetailPenyakitPage({required this.detailPenyakit});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFF9DC08D),
|
||||
appBar: AppBar(
|
||||
backgroundColor: Color(0xFF9DC08D),
|
||||
title: Text(
|
||||
"Detail Penyakit",
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back, color: Colors.white),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
if (detailPenyakit["gambar"] != null && detailPenyakit["gambar"]!.isNotEmpty)
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Image.asset(
|
||||
detailPenyakit["gambar"]!,
|
||||
height: 200,
|
||||
width: 200, // Biar gambar full lebar
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
|
||||
// Card Nama Penyakit
|
||||
SizedBox(
|
||||
width: double.infinity, // Bikin card full lebar
|
||||
child: Card(
|
||||
elevation: 6,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Nama Penyakit:",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
detailPenyakit["nama penyakit"] ?? "Nama penyakit tidak tersedia",
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
|
||||
// Card Deskripsi + Penanganan
|
||||
SizedBox(
|
||||
width: double.infinity, // Bikin card full lebar
|
||||
child: Card(
|
||||
elevation: 6,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Deskripsi:",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
detailPenyakit["deskripsi"] ?? "Deskripsi tidak tersedia",
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
"Penanganan:",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
detailPenyakit["penanganan"] ?? "Penanganan tidak tersedia",
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,56 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/api_services/api_services.dart'; // Pastikan path-nya sesuai
|
||||
|
||||
class ForgotPasswordPage extends StatefulWidget {
|
||||
@override
|
||||
_ForgotPasswordPageState createState() => _ForgotPasswordPageState();
|
||||
}
|
||||
|
||||
class _ForgotPasswordPageState extends State<ForgotPasswordPage> {
|
||||
final TextEditingController emailController = TextEditingController();
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
bool isLoading = false;
|
||||
|
||||
void handleForgotPassword() async {
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
|
||||
try {
|
||||
await apiService.forgotPassword(
|
||||
email: emailController.text.trim(),
|
||||
newPassword: passwordController.text.trim(),
|
||||
);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
title: Text('Berhasil'),
|
||||
content: Text('Password berhasil direset.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('OK'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // tutup dialog
|
||||
Navigator.of(context).pop(); // kembali ke halaman sebelumnya
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(e.toString())),
|
||||
);
|
||||
} finally {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Halaman Lupa Password
|
||||
class ForgotPasswordPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
@ -24,6 +73,7 @@ class ForgotPasswordPage extends StatelessWidget {
|
|||
child: Column(
|
||||
children: [
|
||||
TextField(
|
||||
controller: emailController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Email',
|
||||
border: OutlineInputBorder(
|
||||
|
@ -32,6 +82,17 @@ class ForgotPasswordPage extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
TextField(
|
||||
controller: passwordController,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Password Baru',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
|
@ -42,10 +103,10 @@ class ForgotPasswordPage extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
// Logic reset password
|
||||
},
|
||||
child: Text(
|
||||
onPressed: isLoading ? null : handleForgotPassword,
|
||||
child: isLoading
|
||||
? CircularProgressIndicator(color: Colors.white)
|
||||
: Text(
|
||||
'Reset Password',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'detail_hama_page.dart';
|
||||
|
||||
class HamaPage extends StatelessWidget {
|
||||
final List<Map<String, String>> hamaList = [
|
||||
{
|
||||
"nama hama": "Karat Putih",
|
||||
"deskripsi": "Penyakit yang umum pada bayam.",
|
||||
"penanganan": "Gunakan fungisida sesuai anjuran dan potong daun yang terinfeksi.",
|
||||
"gambar": "assets/images/karat putih.jpeg",
|
||||
},
|
||||
{
|
||||
"nama hama": "Virus Keriting",
|
||||
"deskripsi": "Disebabkan oleh infeksi virus.",
|
||||
"penanganan": "Musnahkan tanaman terinfeksi dan kontrol vektor seperti kutu daun.",
|
||||
"gambar": "assets/images/virus_keriting.jpeg",
|
||||
},
|
||||
{
|
||||
"nama hama": "Kekurangan Mangan",
|
||||
"deskripsi": "Kekurangan unsur hara mikro.",
|
||||
"penanganan": "Tambahkan pupuk yang mengandung mangan (Mn).",
|
||||
"gambar": "assets/images/kekurangan_mangan.jpeg",
|
||||
},
|
||||
{
|
||||
"nama hama": "Downy Mildew",
|
||||
"deskripsi": "Penyakit jamur pada bayam.",
|
||||
"penanganan": "Gunakan fungisida berbahan aktif metalaxyl dan perbaiki drainase tanah.",
|
||||
"gambar": "assets/images/downy_mildew.jpeg",
|
||||
},
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFF9DC08D),
|
||||
appBar: AppBar(
|
||||
backgroundColor: Color(0xFF9DC08D),
|
||||
title: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 30),
|
||||
child: Text(
|
||||
"Hama",
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back, color: Colors.white),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: hamaList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final diagnosa = hamaList[index];
|
||||
return Card(
|
||||
elevation: 4,
|
||||
margin: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
diagnosa["nama hama"] ?? "Tidak ada data",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
subtitle: Text(diagnosa["deskripsi"] ?? "Deskripsi tidak tersedia"),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DetailHamaPage(detailRiwayat: diagnosa),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -73,14 +73,21 @@ class HomePage extends StatelessWidget {
|
|||
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
child: Wrap(
|
||||
spacing: 20, // Jarak horizontal antar tombol
|
||||
runSpacing: 20, // Jarak vertikal antar baris tombol
|
||||
alignment: WrapAlignment.center, // Menempatkan tombol di tengah
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
ButtonMenu(
|
||||
title: "Riwayat Diagnosa",
|
||||
icon: Icons.medical_services,
|
||||
customIcon: Image.asset(
|
||||
'assets/images/Order History.png',
|
||||
width: 48,
|
||||
height: 48,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
|
@ -92,7 +99,11 @@ class HomePage extends StatelessWidget {
|
|||
),
|
||||
ButtonMenu(
|
||||
title: "Profile",
|
||||
icon: Icons.bug_report,
|
||||
customIcon: Image.asset(
|
||||
'assets/images/Test Account.png',
|
||||
width: 48,
|
||||
height: 48,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
|
@ -110,7 +121,11 @@ class HomePage extends StatelessWidget {
|
|||
children: [
|
||||
ButtonMenu(
|
||||
title: "Basis Pengetahuan",
|
||||
icon: Icons.info,
|
||||
customIcon: Image.asset(
|
||||
'assets/images/Literature.png',
|
||||
width: 48,
|
||||
height: 48,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
|
@ -122,7 +137,11 @@ class HomePage extends StatelessWidget {
|
|||
),
|
||||
ButtonMenu(
|
||||
title: "Info Pakar",
|
||||
icon: Icons.exit_to_app,
|
||||
customIcon: Image.asset(
|
||||
'assets/images/Businessman.png',
|
||||
width: 48,
|
||||
height: 48,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
|
@ -148,12 +167,12 @@ class HomePage extends StatelessWidget {
|
|||
// Widget untuk tombol menu
|
||||
class ButtonMenu extends StatelessWidget {
|
||||
final String title;
|
||||
final IconData icon;
|
||||
final Widget customIcon;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const ButtonMenu({
|
||||
required this.title,
|
||||
required this.icon,
|
||||
required this.customIcon,
|
||||
required this.onTap,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
@ -175,10 +194,11 @@ class ButtonMenu extends StatelessWidget {
|
|||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, size: 30, color: Colors.green), // Ikon
|
||||
customIcon,
|
||||
const SizedBox(height: 5),
|
||||
Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'detail_penyakit_page.dart';
|
||||
|
||||
class PenyakitPage extends StatelessWidget {
|
||||
final List<Map<String, String>> penyakitList= [
|
||||
{
|
||||
"nama penyakit": "Karat Putih",
|
||||
"deskripsi": "Penyakit yang umum pada bayam.",
|
||||
"penanganan": "Gunakan fungisida sesuai anjuran dan potong daun yang terinfeksi.",
|
||||
"gambar": "assets/images/karat putih.jpeg",
|
||||
},
|
||||
{
|
||||
"nama penyakit": "Virus Keriting",
|
||||
"deskripsi": "Disebabkan oleh infeksi virus.",
|
||||
"penanganan": "Musnahkan tanaman terinfeksi dan kontrol vektor seperti kutu daun.",
|
||||
"gambar": "assets/images/virus_keriting.jpeg",
|
||||
},
|
||||
{
|
||||
"nama penyakit": "Kekurangan Mangan",
|
||||
"deskripsi": "Kekurangan unsur hara mikro.",
|
||||
"penanganan": "Tambahkan pupuk yang mengandung mangan (Mn).",
|
||||
"gambar": "assets/images/kekurangan_mangan.jpeg",
|
||||
},
|
||||
{
|
||||
"nama penyakit": "Downy Mildew",
|
||||
"deskripsi": "Penyakit jamur pada bayam.",
|
||||
"penanganan": "Gunakan fungisida berbahan aktif metalaxyl dan perbaiki drainase tanah.",
|
||||
"gambar": "assets/images/downy_mildew.jpeg",
|
||||
},
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFF9DC08D),
|
||||
appBar: AppBar(
|
||||
backgroundColor: Color(0xFF9DC08D),
|
||||
title: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 30),
|
||||
child: Text(
|
||||
"Penyakit",
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back, color: Colors.white),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: penyakitList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final diagnosa = penyakitList[index];
|
||||
return Card(
|
||||
elevation: 4,
|
||||
margin: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
diagnosa["nama penyakit"] ?? "Tidak ada data",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
subtitle: Text(diagnosa["deskripsi"] ?? "Deskripsi tidak tersedia"),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DetailPenyakitPage(detailPenyakit: diagnosa),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,16 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/api_services/api_services.dart';
|
||||
|
||||
// Halaman Pendaftaran
|
||||
class RegisterPage extends StatelessWidget {
|
||||
final TextEditingController nameController = TextEditingController();
|
||||
final TextEditingController emailController = TextEditingController();
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
final TextEditingController alamatController = TextEditingController();
|
||||
final TextEditingController nomorHpController = TextEditingController();
|
||||
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
@ -30,6 +39,7 @@ class RegisterPage extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
controller: nameController,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
TextField(
|
||||
|
@ -39,6 +49,7 @@ class RegisterPage extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
controller: emailController,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
TextField(
|
||||
|
@ -49,6 +60,7 @@ class RegisterPage extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
controller: passwordController,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
TextField(
|
||||
|
@ -58,6 +70,7 @@ class RegisterPage extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
controller: emailController,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
TextField(
|
||||
|
@ -67,6 +80,7 @@ class RegisterPage extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
controller: alamatController,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
TextField(
|
||||
|
@ -76,6 +90,7 @@ class RegisterPage extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
controller: nomorHpController,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
SizedBox(
|
||||
|
@ -88,8 +103,24 @@ class RegisterPage extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
// Logic Pendaftaran
|
||||
onPressed: () async {
|
||||
try {
|
||||
await apiService.registerUser(
|
||||
name: nameController.text,
|
||||
email: emailController.text,
|
||||
password: passwordController.text,
|
||||
alamat: alamatController.text,
|
||||
nomorTelepon: nomorHpController.text,
|
||||
);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Registrasi berhasil!')),
|
||||
);
|
||||
Navigator.pop(context); // kembali ke login page
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Registrasi gagal: $e')),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
'Daftar',
|
||||
|
|
|
@ -7,7 +7,8 @@ class RiwayatDiagnosaPage extends StatelessWidget {
|
|||
"deskripsi": "Penyakit yang umum pada bayam.",
|
||||
"penyakit": "Karat Putih",
|
||||
"hama": "Tidak ada hama spesifik",
|
||||
"penanganan": "Gunakan fungisida sesuai anjuran dan potong daun yang terinfeksi."
|
||||
"penanganan": "Gunakan fungisida sesuai anjuran dan potong daun yang terinfeksi.",
|
||||
"gambar": "assets/images/karat putih.jpeg",
|
||||
},
|
||||
{
|
||||
"nama": "Virus Keriting",
|
||||
|
@ -76,11 +77,12 @@ class RiwayatDiagnosaPage extends StatelessWidget {
|
|||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => HasilDiagnosaPage(
|
||||
hasilDiagnosa: {
|
||||
builder: (context) => DetailRiwayatPage(
|
||||
detailRiwayat: {
|
||||
"penyakit": diagnosa["penyakit"] ?? "",
|
||||
"hama": diagnosa["hama"] ?? "",
|
||||
"penanganan": diagnosa["penanganan"] ?? "",
|
||||
"gambar": diagnosa["gambar"] ?? "",
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -98,20 +100,21 @@ class RiwayatDiagnosaPage extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class HasilDiagnosaPage extends StatelessWidget {
|
||||
final Map<String, String> hasilDiagnosa;
|
||||
class DetailRiwayatPage extends StatelessWidget {
|
||||
final Map<String, String> detailRiwayat;
|
||||
|
||||
HasilDiagnosaPage({required this.hasilDiagnosa});
|
||||
DetailRiwayatPage({required this.detailRiwayat});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFF9DC08D),
|
||||
appBar: AppBar(
|
||||
backgroundColor: Color(0xFF9DC08D),
|
||||
title: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 30), // Geser ke kiri
|
||||
padding: const EdgeInsets.only(right: 30),
|
||||
child: Text(
|
||||
"Hasil Diagnosa",
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white),
|
||||
|
@ -123,51 +126,65 @@ class HasilDiagnosaPage extends StatelessWidget {
|
|||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
color: Color(0xFF9DC08D),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
if (detailRiwayat['gambar'] != null)
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Image.asset(
|
||||
detailRiwayat['gambar']!,
|
||||
height: 200,
|
||||
width: 200,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Card(
|
||||
elevation: 6,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Center(
|
||||
child: Card(
|
||||
elevation: 6,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Container(
|
||||
width: 400,
|
||||
height: 300, // Mengatur ukuran card
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Nama Penyakit: ${hasilDiagnosa['penyakit']}",
|
||||
style: TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black),
|
||||
"Nama Penyakit: ${detailRiwayat['penyakit']}",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
"Nama Hama: ${hasilDiagnosa['hama']}",
|
||||
style: TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black),
|
||||
"Nama Hama: ${detailRiwayat['hama']}",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Card(
|
||||
elevation: 6,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Cara Penanganan:",
|
||||
style: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black),
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
hasilDiagnosa['penanganan'] ?? "Data tidak tersedia",
|
||||
detailRiwayat['penanganan'] ?? "Data tidak tersedia",
|
||||
style: TextStyle(fontSize: 16, color: Colors.black),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -62,6 +62,13 @@ flutter:
|
|||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/images/bayam.png
|
||||
- assets/images/Businessman.png
|
||||
- assets/images/Literature.png
|
||||
- assets/images/Order History.png
|
||||
- assets/images/Test Account.png
|
||||
- assets/images/Virus.png
|
||||
- assets/images/Caterpillar.png
|
||||
- assets/images/karat putih.jpeg
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/to/resolution-aware-images
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
// This is a basic Flutter widget test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility in the flutter_test package. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:frontend/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(const MyApp());
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsNothing);
|
||||
|
||||
// Tap the '+' icon and trigger a frame.
|
||||
await tester.tap(find.byIcon(Icons.add));
|
||||
await tester.pump();
|
||||
|
||||
// Verify that our counter has incremented.
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|