MIF_E31232435/lib/screens/transaction_screen.dart

1129 lines
46 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:finalproject/theme/colors.dart';
import 'package:finalproject/theme/text_styles.dart';
import 'package:finalproject/models/transaction_model.dart';
import 'package:finalproject/services/ml_service.dart';
class CartItem {
final String productName;
final String category;
final int unitPrice;
int quantity;
CartItem({
required this.productName,
required this.category,
required this.unitPrice,
required this.quantity,
});
int get totalPrice => unitPrice * quantity;
}
class TransactionScreen extends StatefulWidget {
const TransactionScreen({Key? key}) : super(key: key);
@override
State<TransactionScreen> createState() => _TransactionScreenState();
}
class _TransactionScreenState extends State<TransactionScreen> {
late TextEditingController _quantityController;
DateTime? _selectedDate;
bool _isLoading = false;
int _selectedIndex = 2; // Transaction tab
// Products list (mutable)
late List<String> products;
late Map<String, String> productCategories;
late Map<String, int> productPrices;
late List<String> categories;
String? _selectedProduct;
List<CartItem> cartItems = [];
List<Transaction> transactions = [];
@override
void initState() {
super.initState();
_quantityController = TextEditingController();
_selectedDate = DateTime.now();
_loadProducts();
}
Future<void> _loadProducts() async {
try {
final fetchedProducts = await MLService.getProducts();
setState(() {
products = [];
productCategories = {};
productPrices = {};
categories = [];
// Convert API response to local maps
for (var product in fetchedProducts) {
String name = product['name'] ?? '';
String category = product['category'] ?? '';
int price = product['price'] ?? 0;
if (name.isNotEmpty) {
products.add(name);
productCategories[name] = category;
productPrices[name] = price;
if (!categories.contains(category)) {
categories.add(category);
}
}
}
});
} catch (e) {
print('Error loading products: $e');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Gagal memuat data produk'),
backgroundColor: AppColors.statusError,
),
);
}
}
@override
void dispose() {
_quantityController.dispose();
super.dispose();
}
void _addToCart() {
if (_selectedProduct == null || _quantityController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Pilih produk dan masukkan jumlah'),
backgroundColor: AppColors.statusError,
),
);
return;
}
final quantity = int.tryParse(_quantityController.text) ?? 0;
if (quantity <= 0) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Jumlah harus lebih dari 0'),
backgroundColor: AppColors.statusError,
),
);
return;
}
final existingIndex =
cartItems.indexWhere((item) => item.productName == _selectedProduct);
setState(() {
if (existingIndex >= 0) {
// Update quantity if product already in cart
cartItems[existingIndex].quantity += quantity;
} else {
// Add new item to cart
cartItems.add(
CartItem(
productName: _selectedProduct!,
category: productCategories[_selectedProduct!]!,
unitPrice: productPrices[_selectedProduct!]!,
quantity: quantity,
),
);
}
_quantityController.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('$_selectedProduct ditambahkan ke keranjang'),
backgroundColor: AppColors.statusSuccess,
),
);
}
void _removeFromCart(int index) {
setState(() {
cartItems.removeAt(index);
});
}
void _updateQuantity(int index, int newQuantity) {
if (newQuantity <= 0) {
_removeFromCart(index);
} else {
setState(() {
cartItems[index].quantity = newQuantity;
});
}
}
int _getTotalPrice() {
return cartItems.fold(0, (total, item) => total + item.totalPrice);
}
void _submitAllTransactions() async {
if (cartItems.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Keranjang kosong'),
backgroundColor: AppColors.statusError,
),
);
return;
}
setState(() => _isLoading = true);
try {
final dateStr =
'${_selectedDate!.year}-${_selectedDate!.month.toString().padLeft(2, '0')}-${_selectedDate!.day.toString().padLeft(2, '0')}';
for (final item in cartItems) {
await MLService.saveTransaction(
productName: item.productName,
category: item.category,
quantity: item.quantity,
unitPrice: item.unitPrice,
totalPrice: item.totalPrice,
transactionDate: dateStr,
);
// Add to transaction history
final transaction = Transaction(
id: transactions.length + 1,
productName: item.productName,
category: item.category,
quantity: item.quantity,
unitPrice: item.unitPrice,
totalPrice: item.totalPrice,
date: _selectedDate ?? DateTime.now(),
);
transactions.insert(0, transaction);
}
setState(() {
_isLoading = false;
cartItems.clear();
_selectedDate = DateTime.now();
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('${transactions.length} transaksi berhasil disimpan!'),
backgroundColor: AppColors.statusSuccess,
),
);
} catch (e) {
setState(() => _isLoading = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error: ${e.toString()}'),
backgroundColor: AppColors.statusError,
),
);
}
}
void _showAddProductDialog() {
final TextEditingController newProductNameController =
TextEditingController();
final TextEditingController newCategoryController = TextEditingController();
final TextEditingController newPriceController = TextEditingController();
String _selectedCategory = categories.isNotEmpty ? categories.first : '';
bool _createNewCategory = false;
showDialog(
context: context,
builder: (context) => StatefulBuilder(
builder: (context, setStateDialog) => Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Container(
decoration: BoxDecoration(
color: AppColors.bgWhite,
borderRadius: BorderRadius.circular(16),
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Container(
width: double.infinity,
decoration: BoxDecoration(
color: AppColors.primaryBrown,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
padding: const EdgeInsets.all(16),
child: Text(
'Tambah Produk Baru',
style: AppTextStyles.headlineSmall.copyWith(
color: Colors.white,
),
),
),
Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Product Name
Text(
'Nama Produk',
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.textPrimary,
),
),
const SizedBox(height: 8),
TextFormField(
controller: newProductNameController,
decoration: InputDecoration(
hintText: 'Masukkan nama produk',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: AppColors.bgLight,
),
),
const SizedBox(height: 16),
// Category Selection
Text(
'Kategori',
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.textPrimary,
),
),
const SizedBox(height: 8),
if (!_createNewCategory)
Column(
children: [
DropdownButtonFormField<String>(
value: _selectedCategory.isNotEmpty
? _selectedCategory
: null,
items: categories
.map((cat) => DropdownMenuItem(
value: cat,
child: Text(cat),
))
.toList(),
onChanged: (value) {
setStateDialog(
() => _selectedCategory = value ?? '',
);
},
decoration: InputDecoration(
hintText: 'Pilih kategori',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: AppColors.bgLight,
),
),
const SizedBox(height: 8),
GestureDetector(
onTap: () {
setStateDialog(
() => _createNewCategory = true);
},
child: Text(
'+ Tambah kategori baru',
style: AppTextStyles.labelMedium.copyWith(
color: AppColors.secondaryBlue,
fontWeight: FontWeight.w600,
),
),
),
],
)
else
Column(
children: [
TextFormField(
controller: newCategoryController,
decoration: InputDecoration(
hintText: 'Masukkan nama kategori baru',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: AppColors.bgLight,
),
),
const SizedBox(height: 8),
GestureDetector(
onTap: () {
setStateDialog(
() => _createNewCategory = false);
newCategoryController.clear();
},
child: Text(
'← Kembali ke kategori existing',
style: AppTextStyles.labelMedium.copyWith(
color: AppColors.textSecondary,
fontWeight: FontWeight.w600,
),
),
),
],
),
const SizedBox(height: 16),
// Price
Text(
'Harga (Rp)',
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.textPrimary,
),
),
const SizedBox(height: 8),
TextFormField(
controller: newPriceController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Masukkan harga',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: AppColors.bgLight,
),
),
const SizedBox(height: 24),
// Buttons
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => Navigator.pop(context),
style: OutlinedButton.styleFrom(
padding:
const EdgeInsets.symmetric(vertical: 12),
side: BorderSide(
color: AppColors.textSecondary,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: Text(
'Batal',
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.textSecondary,
),
),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () async {
final productName =
newProductNameController.text.trim();
final category = _createNewCategory
? newCategoryController.text.trim()
: _selectedCategory;
final price = newPriceController.text.trim();
if (productName.isEmpty ||
category.isEmpty ||
price.isEmpty) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: const Text(
'Semua field harus diisi'),
backgroundColor:
AppColors.statusError,
),
);
return;
}
final priceInt =
int.tryParse(price) ?? 0;
if (priceInt <= 0) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: const Text(
'Harga harus lebih dari 0'),
backgroundColor:
AppColors.statusError,
),
);
return;
}
// Frontend validation: check duplicate
if (products.contains(productName)) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'Produk "$productName" sudah ada'),
backgroundColor:
AppColors.statusError,
),
);
return;
}
// Call API to create product
setStateDialog(() {
// Show loading in dialog via disabling button
});
final result =
await MLService.createProduct(
name: productName,
category: category,
price: priceInt,
currentStock: 0, // Default stock 0
);
if (!mounted) return;
if (result['status'] == 'success') {
// Add to local state for immediate UI update
setState(() {
products.add(productName);
productCategories[productName] =
category;
productPrices[productName] = priceInt;
if (_createNewCategory &&
!categories.contains(category)) {
categories.add(category);
}
});
Navigator.pop(context);
// Show success message
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'Produk "$productName" berhasil ditambahkan'),
backgroundColor:
AppColors.statusSuccess,
),
);
} else {
// Handle error from API
String errorMsg = result['message'] ??
'Gagal menambahkan produk';
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(errorMsg),
backgroundColor:
AppColors.statusError,
),
);
}
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBrown,
padding: const EdgeInsets.symmetric(
vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: Text(
'Simpan',
style: AppTextStyles.labelLarge.copyWith(
color: Colors.white,
),
),
),
),
],
),
],
),
),
],
),
),
),
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bgLight,
appBar: AppBar(
backgroundColor: AppColors.primaryBrown,
elevation: 0,
title: Text(
'Transaksi Penjualan',
style: AppTextStyles.headlineLarge.copyWith(
color: Colors.white,
),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.pop(context),
),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Form card untuk memilih produk
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColors.bgWhite,
borderRadius: BorderRadius.circular(16),
boxShadow: [AppColors.shadowLight],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Pilih Produk',
style: AppTextStyles.headlineSmall.copyWith(
color: AppColors.textPrimary,
),
),
const SizedBox(height: 16),
// Product dropdown
Text(
'Produk',
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.textPrimary,
),
),
const SizedBox(height: 8),
DropdownButtonFormField<String>(
value: _selectedProduct,
decoration: InputDecoration(
hintText: 'Pilih produk',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: AppColors.bgLight,
),
items: products
.map((product) => DropdownMenuItem(
value: product,
child: Text(product),
))
.toList(),
onChanged: (value) {
setState(() => _selectedProduct = value);
},
),
const SizedBox(height: 24),
// Quantity input
Text(
'Jumlah',
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.textPrimary,
),
),
const SizedBox(height: 8),
TextField(
controller: _quantityController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Masukkan jumlah unit',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: AppColors.bgLight,
),
),
const SizedBox(height: 24),
// Add to cart button
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: _addToCart,
icon: const Icon(Icons.add_shopping_cart),
label: const Text('Tambah ke Keranjang'),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBrown,
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
),
const SizedBox(height: 16),
// Add new product button
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: _showAddProductDialog,
icon: const Icon(Icons.add_circle_outline),
label: const Text('Tambah Produk Baru'),
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
side: BorderSide(
color: AppColors.secondaryBlue,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
),
],
),
),
const SizedBox(height: 24),
// Cart section
if (cartItems.isNotEmpty) ...[
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColors.bgWhite,
borderRadius: BorderRadius.circular(16),
boxShadow: [AppColors.shadowLight],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Keranjang (${cartItems.length})',
style: AppTextStyles.headlineSmall.copyWith(
color: AppColors.textPrimary,
),
),
GestureDetector(
onTap: () {
setState(() => cartItems.clear());
},
child: Text(
'Hapus Semua',
style: AppTextStyles.labelMedium.copyWith(
color: AppColors.statusError,
fontWeight: FontWeight.w600,
),
),
),
],
),
const SizedBox(height: 16),
// Cart items list
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: cartItems.length,
itemBuilder: (context, index) {
final item = cartItems[index];
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColors.bgLight,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: AppColors.grey300),
),
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
item.productName,
style: AppTextStyles.labelLarge
.copyWith(
color: AppColors.textPrimary,
),
),
const SizedBox(height: 4),
Text(
'Rp ${item.unitPrice} / unit',
style: AppTextStyles.labelSmall
.copyWith(
color: AppColors.textSecondary,
),
),
],
),
),
Text(
'Rp ${item.totalPrice}',
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.statusSuccess,
fontWeight: FontWeight.w700,
),
),
],
),
const SizedBox(height: 12),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
// Quantity controls
Row(
children: [
GestureDetector(
onTap: () =>
_updateQuantity(index, item.quantity - 1),
child: Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: AppColors.primaryBrown,
borderRadius:
BorderRadius.circular(6),
),
child: const Icon(
Icons.remove,
color: Colors.white,
size: 18,
),
),
),
const SizedBox(width: 12),
Text(
item.quantity.toString(),
style: AppTextStyles.labelLarge
.copyWith(
color: AppColors.textPrimary,
fontWeight: FontWeight.w600,
),
),
const SizedBox(width: 12),
GestureDetector(
onTap: () =>
_updateQuantity(index, item.quantity + 1),
child: Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: AppColors.primaryBrown,
borderRadius:
BorderRadius.circular(6),
),
child: const Icon(
Icons.add,
color: Colors.white,
size: 18,
),
),
),
],
),
// Delete button
GestureDetector(
onTap: () => _removeFromCart(index),
child: Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: AppColors.statusError
.withOpacity(0.1),
borderRadius:
BorderRadius.circular(6),
),
child: Icon(
Icons.delete,
color: AppColors.statusError,
size: 18,
),
),
),
],
),
],
),
);
},
),
const SizedBox(height: 16),
const Divider(),
const SizedBox(height: 12),
// Total price
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Pembayaran',
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.textPrimary,
),
),
Text(
'Rp ${_getTotalPrice()}',
style: AppTextStyles.headlineSmall.copyWith(
color: AppColors.primaryBrown,
fontWeight: FontWeight.w700,
),
),
],
),
const SizedBox(height: 16),
// Date picker
Text(
'Tanggal Transaksi',
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.textPrimary,
),
),
const SizedBox(height: 8),
GestureDetector(
onTap: () async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: _selectedDate ?? DateTime.now(),
firstDate: DateTime(2020),
lastDate: DateTime.now(),
);
if (picked != null && picked != _selectedDate) {
setState(() => _selectedDate = picked);
}
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
decoration: BoxDecoration(
border: Border.all(color: AppColors.grey300),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
const Icon(
Icons.calendar_today,
color: AppColors.primaryBrown,
),
const SizedBox(width: 12),
Text(
_selectedDate != null
? '${_selectedDate!.day}/${_selectedDate!.month}/${_selectedDate!.year}'
: 'Pilih tanggal',
style: AppTextStyles.bodyMedium,
),
],
),
),
),
const SizedBox(height: 24),
// Submit button
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: _isLoading ? null : _submitAllTransactions,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBrown,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
icon: _isLoading
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
Colors.white,
),
),
)
: const Icon(Icons.check_circle),
label: Text(
_isLoading ? 'Menyimpan...' : 'Simpan Transaksi',
style: AppTextStyles.labelLarge,
),
),
),
],
),
),
const SizedBox(height: 24),
],
// Transactions history
Text(
'Riwayat Transaksi (${transactions.length})',
style: AppTextStyles.headlineSmall.copyWith(
color: AppColors.textPrimary,
),
),
const SizedBox(height: 16),
if (transactions.isEmpty)
Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 32.0),
child: Column(
children: [
Icon(Icons.inbox, size: 64, color: AppColors.grey300),
const SizedBox(height: 16),
Text(
'Belum ada transaksi',
style: AppTextStyles.bodyMedium.copyWith(
color: AppColors.textSecondary,
),
),
],
),
),
)
else
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: transactions.length,
itemBuilder: (context, index) {
final tx = transactions[index];
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColors.bgWhite,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.grey200),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
tx.productName,
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.textPrimary,
),
),
Text(
'Rp ${tx.totalPrice}',
style: AppTextStyles.labelLarge.copyWith(
color: AppColors.statusSuccess,
fontWeight: FontWeight.w700,
),
),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${tx.quantity} unit × Rp ${tx.unitPrice}',
style: AppTextStyles.labelMedium.copyWith(
color: AppColors.textSecondary,
),
),
Text(
'${tx.date.day}/${tx.date.month}/${tx.date.year}',
style: AppTextStyles.labelSmall.copyWith(
color: AppColors.textSecondary,
),
),
],
),
],
),
);
},
),
],
),
),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: (index) {
setState(() => _selectedIndex = index);
switch (index) {
case 0:
Navigator.of(context).pushNamed('/dashboard');
break;
case 1:
Navigator.of(context).pushNamed('/products');
break;
case 2:
break;
case 3:
Navigator.of(context).pushNamed('/prediction');
break;
case 4:
Navigator.of(context).pushNamed('/reports');
break;
}
},
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.white,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home_outlined),
label: 'Dashboard',
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_bag_outlined),
label: 'Produk',
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart_outlined),
label: 'Transaksi',
),
BottomNavigationBarItem(
icon: Icon(Icons.trending_up_outlined),
label: 'Prediksi',
),
BottomNavigationBarItem(
icon: Icon(Icons.description_outlined),
label: 'Laporan',
),
],
),
);
}
}