import 'package:flutter/material.dart';
import 'dart:html' as html;
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Kantin Sekolah RASA NIKMAT",
theme: ThemeData(
primarySwatch: Colors.deepOrange,
fontFamily: 'Poppins',
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFFE65100),
elevation: 4,
centerTitle: true,
),
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.deepOrange,
brightness: Brightness.light,
),
),
home: const HomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final List<Map<String, dynamic>> _allProducts = [
{
"id": 1,
"name": "Mie Ayam Bakso",
"price": 15000,
"qty": 0,
"image": "https://images.unsplash.com/photo-1586190848861-99aa4a171e90?q=80&w=400&auto=format&fit=crop",
"category": "Makanan Berat",
"rating": 4.8,
"description": "Mie ayam dengan bakso sapi pilihan",
},
{
"id": 2,
"name": "Nasi Goreng Special",
"price": 12000,
"qty": 0,
"image": "https://images.unsplash.com/photo-1633945274417-b8c0b5dada04?q=80&w=400&auto=format&fit=crop",
"category": "Makanan Berat",
"rating": 4.7,
"description": "Nasi goreng dengan telur dan ayam",
},
{
"id": 3,
"name": "Batagor",
"price": 8000,
"qty": 0,
"image": "https://images.unsplash.com/photo-1563379091339-03246963d9d6?q=80&w=400&auto=format&fit=crop",
"category": "Snack",
"rating": 4.5,
"description": "Bakso tahu goreng dengan bumbu kacang",
},
{
"id": 4,
"name": "Es Teh Manis",
"price": 3000,
"qty": 0,
"image": "https://images.unsplash.com/photo-1568649929103-28ffbefaca1e?q=80&w=400&auto=format&fit=crop",
"category": "Minuman",
"rating": 4.3,
"description": "Es teh dengan gula pasir",
},
{
"id": 5,
"name": "Sate Ayam",
"price": 10000,
"qty": 0,
"image": "https://images.unsplash.com/photo-1594488506255-a8c8b4d8dc5e?q=80&w=400&auto=format&fit=crop",
"category": "Makanan Berat",
"rating": 4.6,
"description": "10 tusuk sate ayam dengan bumbu kacang",
},
{
"id": 6,
"name": "Es Jeruk",
"price": 5000,
"qty": 0,
"image": "https://images.unsplash.com/photo-1621506289937-a8e4df240d0b?q=80&w=400&auto=format&fit=crop",
"category": "Minuman",
"rating": 4.4,
"description": "Es jeruk segar",
},
{
"id": 7,
"name": "Roti Bakar",
"price": 7000,
"qty": 0,
"image": "https://images.unsplash.com/photo-1488477181946-6428a0291777?q=80&w=400&auto=format&fit=crop",
"category": "Snack",
"rating": 4.5,
"description": "Roti bakar coklat keju",
},
{
"id": 8,
"name": "Air Mineral",
"price": 2000,
"qty": 0,
"image": "https://images.unsplash.com/photo-1523362628745-0c100150b504?q=80&w=400&auto=format&fit=crop",
"category": "Minuman",
"rating": 4.0,
"description": "Air mineral kemasan 600ml",
},
{
"id": 9,
"name": "Ayam Geprek",
"price": 14000,
"qty": 0,
"image": "https://images.unsplash.com/photo-1562967914-608f82629710?q=80&w=400&auto=format&fit=crop",
"category": "Makanan Berat",
"rating": 4.9,
"description": "Ayam geprek sambal bawang",
},
{
"id": 10,
"name": "Es Campur",
"price": 8000,
"qty": 0,
"image": "https://images.unsplash.com/photo-1572490122747-3968b75cc699?q=80&w=400&auto=format&fit=crop",
"category": "Minuman",
"rating": 4.6,
"description": "Es campur dengan buah segar",
},
];
List<Map<String, dynamic>> _foundProducts = [];
final TextEditingController _searchController = TextEditingController();
int _selectedCategory = 0;
@override
void initState() {
super.initState();
_foundProducts = List.from(_allProducts);
}
void _filterProducts(String query) {
List<Map<String, dynamic>> results = [];
if (query.isEmpty) {
results = List.from(_allProducts);
} else {
results = _allProducts
.where((item) =>
(item['name'] as String).toLowerCase().contains(query.toLowerCase()) ||
(item['category'] as String).toLowerCase().contains(query.toLowerCase()))
.toList();
}
if (_selectedCategory > 0) {
String category = _getCategoryFromIndex(_selectedCategory);
results = results.where((item) => item['category'] == category).toList();
}
setState(() {
_foundProducts = results;
});
}
void _filterByCategory(int index) {
setState(() {
_selectedCategory = index;
});
if (index == 0) {
_filterProducts(_searchController.text);
} else {
String category = _getCategoryFromIndex(index);
setState(() {
_foundProducts = _allProducts
.where((item) => item['category'] == category)
.where((item) =>
_searchController.text.isEmpty ||
(item['name'] as String).toLowerCase().contains(_searchController.text.toLowerCase()))
.toList();
});
}
}
String _getCategoryFromIndex(int index) {
switch (index) {
case 1:
return 'Makanan Berat';
case 2:
return 'Snack';
case 3:
return 'Minuman';
default:
return '';
}
}
@override
Widget build(BuildContext context) {
int totalItems = _allProducts.fold<int>(0, (int sum, item) => sum + (item['qty'] as int));
int totalPrice = _allProducts.fold<int>(0, (int sum, item) => sum + (item['price'] as int) * (item['qty'] as int));
return Scaffold(
appBar: AppBar(
title: Column(
children: [
Text(
"KANTIN RASA NIKMAT",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
"Makanan Hangat & Lezat",
style: TextStyle(
fontSize: 12,
color: Colors.white70,
),
),
],
),
centerTitle: true,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(30),
),
),
),
body: Column(
children: [
// Search Bar
Padding(
padding: EdgeInsets.all(16.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.deepOrange.withOpacity(0.1),
blurRadius: 10,
spreadRadius: 1,
),
],
),
child: TextField(
controller: _searchController,
onChanged: _filterProducts,
decoration: InputDecoration(
hintText: "Cari makanan atau minuman...",
prefixIcon: Icon(Icons.search, color: Colors.deepOrange),
suffixIcon: _searchController.text.isNotEmpty
? IconButton(
icon: Icon(Icons.clear, color: Colors.deepOrange),
onPressed: () {
_searchController.clear();
_filterProducts('');
},
)
: null,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 20, vertical: 15),
),
),
),
),
// Category Filter
SizedBox(
height: 50,
child: ListView(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: 16),
children: [
_buildCategoryChip("Semua", 0),
SizedBox(width: 8),
_buildCategoryChip("Makanan Berat", 1),
SizedBox(width: 8),
_buildCategoryChip("Snack", 2),
SizedBox(width: 8),
_buildCategoryChip("Minuman", 3),
],
),
),
SizedBox(height: 16),
// Cart Summary
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.deepOrange[400]!, Colors.deepOrange[600]!],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.deepOrange.withOpacity(0.3),
blurRadius: 10,
spreadRadius: 2,
),
],
),
child: Row(
children: [
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Icon(Icons.shopping_basket, color: Colors.deepOrange, size: 24),
),
SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Pesanan Anda",
style: TextStyle(
color: Colors.white.withOpacity(0.9),
fontSize: 12,
),
),
Text(
"$totalItems item",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"Total",
style: TextStyle(
color: Colors.white.withOpacity(0.9),
fontSize: 12,
),
),
Text(
"Rp ${totalPrice.toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)}",
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
],
),
),
),
SizedBox(height: 16),
// Products Grid
Expanded(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 12.0),
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 0.75,
),
itemCount: _foundProducts.length,
itemBuilder: (context, index) {
var item = _foundProducts[index];
return _buildProductCard(item);
},
),
),
),
],
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
List<Map<String, dynamic>> cart = _allProducts.where((e) => (e['qty'] as int) > 0).toList();
if (cart.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Belum ada makanan dipilih!"),
backgroundColor: Colors.deepOrange[800],
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
return;
}
Navigator.push(
context,
MaterialPageRoute(builder: (_) => CheckoutPage(cart)),
);
},
label: Text(
"Pesan Sekarang",
style: TextStyle(fontWeight: FontWeight.bold),
),
icon: Icon(Icons.restaurant_menu),
backgroundColor: Color(0xFFE65100),
elevation: 4,
),
);
}
Widget _buildCategoryChip(String text, int index) {
bool isSelected = _selectedCategory == index;
return GestureDetector(
onTap: () => _filterByCategory(index),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
decoration: BoxDecoration(
color: isSelected ? Colors.deepOrange : Colors.grey[200],
borderRadius: BorderRadius.circular(25),
border: Border.all(
color: isSelected ? Colors.deepOrange : Colors.transparent,
width: 1.5,
),
),
child: Text(
text,
style: TextStyle(
color: isSelected ? Colors.white : Colors.grey[700],
fontWeight: FontWeight.w600,
fontSize: 13,
),
),
),
);
}
Widget _buildProductCard(Map<String, dynamic> item) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
blurRadius: 10,
spreadRadius: 2,
offset: Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Product Image
ClipRRect(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
child: Container(
height: 110,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(item['image'] as String),
fit: BoxFit.cover,
),
),
child: Stack(
children: [
// Category Badge
Positioned(
top: 8,
left: 8,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: _getCategoryColor(item['category'] as String).withOpacity(0.9),
borderRadius: BorderRadius.circular(10),
),
child: Text(
item['category'] as String,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: _getCategoryTextColor(item['category'] as String),
),
),
),
),
// Rating Badge
Positioned(
top: 8,
right: 8,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 3),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.amber, size: 12),
SizedBox(width: 2),
Text(
"${item['rating']}",
style: TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
],
),
),
),
// Product Info
Padding(
padding: EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item['name'] as String,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Color(0xFF333333),
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 4),
Text(
item['description'] as String,
style: TextStyle(
fontSize: 11,
color: Colors.grey[600],
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Rp ${(item['price'] as int).toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)}",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Color(0xFFE65100),
),
),
if ((item['qty'] as int) > 0)
Container(
padding: EdgeInsets.symmetric(horizontal: 6),
decoration: BoxDecoration(
color: Colors.deepOrange[100],
borderRadius: BorderRadius.circular(10),
),
child: Text(
"${item['qty']}",
style: TextStyle(
color: Colors.deepOrange,
fontWeight: FontWeight.bold,
),
),
),
],
),
SizedBox(height: 8),
// Quantity Controls
Container(
decoration: BoxDecoration(
color: Colors.grey[50],
borderRadius: BorderRadius.circular(15),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: TextButton(
onPressed: () {
setState(() {
if ((item['qty'] as int) > 0) {
item['qty'] = (item['qty'] as int) - 1;
}
});
},
style: TextButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.horizontal(
left: Radius.circular(15),
),
),
),
child: Icon(
Icons.remove,
color: Colors.grey,
size: 18,
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Text(
"${item['qty']}",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.deepOrange,
),
),
),
Expanded(
child: TextButton(
onPressed: () {
setState(() {
item['qty'] = (item['qty'] as int) + 1;
});
},
style: TextButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.horizontal(
right: Radius.circular(15),
),
),
),
child: Icon(
Icons.add,
color: Colors.deepOrange,
size: 18,
),
),
),
],
),
),
],
),
),
],
),
);
}
Color _getCategoryColor(String category) {
switch (category) {
case 'Makanan Berat':
return Color(0xFFFFF3E0);
case 'Snack':
return Color(0xFFE8F5E9);
case 'Minuman':
return Color(0xFFE3F2FD);
default:
return Color(0xFFF5F5F5);
}
}
Color _getCategoryTextColor(String category) {
switch (category) {
case 'Makanan Berat':
return Color(0xFFE65100);
case 'Snack':
return Color(0xFF2E7D32);
case 'Minuman':
return Color(0xFF1565C0);
default:
return Colors.grey;
}
}
}
class CheckoutPage extends StatefulWidget {
final List<Map<String, dynamic>> cart;
const CheckoutPage(this.cart, {super.key});
@override
State<CheckoutPage> createState() => _CheckoutPageState();
}
class _CheckoutPageState extends State<CheckoutPage> {
final TextEditingController _namaController = TextEditingController();
final TextEditingController _kelasController = TextEditingController();
final TextEditingController _nomorController = TextEditingController();
@override
void initState() {
super.initState();
_nomorController.text = "6282263088566";
}
@override
void dispose() {
_namaController.dispose();
_kelasController.dispose();
_nomorController.dispose();
super.dispose();
}
int get total {
return widget.cart.fold<int>(0, (int sum, item) {
return sum + (item['price'] as int) * (item['qty'] as int);
});
}
int get totalItems {
return widget.cart.fold<int>(0, (int sum, item) => sum + (item['qty'] as int));
}
void _resetForm() {
setState(() {
_namaController.clear();
_kelasController.clear();
_nomorController.text = "6282263088566";
});
}
void _kirimWhatsApp() {
if (_namaController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Harap masukkan nama pemesan!"),
backgroundColor: Colors.red,
),
);
return;
}
if (_kelasController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Harap masukkan kelas!"),
backgroundColor: Colors.red,
),
);
return;
}
if (_nomorController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Harap masukkan nomor WhatsApp!"),
backgroundColor: Colors.red,
),
);
return;
}
// Format pesan WhatsApp
String message = """
*PESANAN KANTIN SEKOLAH RASA NIKMAT*
Nama: ${_namaController.text}
Kelas: ${_kelasController.text}
Waktu: ${DateTime.now().hour}:${DateTime.now().minute.toString().padLeft(2, '0')}
────────────────────
*DETAIL PESANAN:*
""";
for (var item in widget.cart) {
message += """
• ${item['name']}
${item['qty']} x Rp ${(item['price'] as int).toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)} = Rp ${((item['price'] as int) * (item['qty'] as int)).toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)}
""";
}
message += """
────────────────────
*TOTAL: Rp ${total.toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)}*
_Catatan: Pesanan akan diantar ke kelas ${_kelasController.text} pada jam istirahat berikutnya._
Terima kasih!
Kantin Rasa Nikmat 🍽️
""";
String phone = _nomorController.text;
String url = "https://wa.me/$phone?text=${Uri.encodeComponent(message)}";
html.window.open(url, "_blank");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"✅ Pesanan Dikirim ke WhatsApp",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
SizedBox(height: 8),
Text(
"Nama: ${_namaController.text}",
style: TextStyle(fontSize: 14),
),
Text(
"Kelas: ${_kelasController.text}",
style: TextStyle(fontSize: 14),
),
Text(
"Total: Rp ${total.toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)}",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
],
),
backgroundColor: Colors.green[700],
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
duration: Duration(seconds: 5),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Checkout - Kantin Rasa Nikmat"),
backgroundColor: Color(0xFFE65100),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(30),
),
),
),
body: SingleChildScrollView(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Center(
child: Column(
children: [
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.deepOrange[100],
shape: BoxShape.circle,
border: Border.all(color: Colors.deepOrange, width: 3),
boxShadow: [
BoxShadow(
color: Colors.deepOrange.withOpacity(0.3),
blurRadius: 10,
spreadRadius: 2,
),
],
),
child: Icon(
Icons.restaurant,
size: 50,
color: Color(0xFFE65100),
),
),
SizedBox(height: 16),
Text(
"Selesaikan Pesanan Anda",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Color(0xFFE65100),
),
),
SizedBox(height: 8),
Text(
"Isi data diri untuk pengiriman pesanan",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: Colors.grey[700],
),
),
],
),
),
SizedBox(height: 24),
// Form Input
Column(
children: [
_buildInputField(
controller: _namaController,
label: "Nama Lengkap",
icon: Icons.person,
hint: "Masukkan nama lengkap",
),
SizedBox(height: 16),
_buildInputField(
controller: _kelasController,
label: "Kelas",
icon: Icons.school,
hint: "Contoh: XII IPA 1",
),
SizedBox(height: 16),
_buildInputField(
controller: _nomorController,
label: "Nomor WhatsApp",
icon: Icons.phone,
hint: "6282263088566",
isPhone: true,
),
],
),
SizedBox(height: 24),
// Order Summary
Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.deepOrange[50],
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.deepOrange[100]!),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.receipt, color: Colors.deepOrange),
SizedBox(width: 8),
Text(
"Ringkasan Pesanan",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.deepOrange,
),
),
],
),
SizedBox(height: 16),
...widget.cart.map((item) => Padding(
padding: EdgeInsets.only(bottom: 12),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(
image: NetworkImage(item['image'] as String),
fit: BoxFit.cover,
),
),
),
SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item['name'] as String,
style: TextStyle(
fontWeight: FontWeight.w600,
),
),
Text(
"${item['qty']} x Rp ${(item['price'] as int).toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)}",
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
),
),
Text(
"Rp ${((item['price'] as int) * (item['qty'] as int)).toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)}",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.deepOrange,
),
),
],
),
)),
Divider(height: 30),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Total Item:",
style: TextStyle(fontSize: 16, color: Colors.grey),
),
Text(
"$totalItems item",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Total Pembayaran:",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.deepOrange,
),
),
Text(
"Rp ${total.toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)}",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.deepOrange,
),
),
],
),
],
),
),
SizedBox(height: 24),
// Information Card
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.amber[50],
borderRadius: BorderRadius.circular(15),
border: Border.all(color: Colors.amber[100]!),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.info_outline, color: Colors.amber, size: 20),
SizedBox(width: 8),
Text(
"Informasi Penting",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.amber,
),
),
],
),
SizedBox(height: 8),
Text(
"• Pesanan diantar saat jam istirahat\n"
"• Pembayaran saat barang diterima\n"
"• Hubungi kantin jika ada perubahan\n"
"• Jam operasional: 07.00 - 15.00 WIB",
style: TextStyle(fontSize: 13, height: 1.5),
),
],
),
),
SizedBox(height: 24),
// Action Buttons
Row(
children: [
Expanded(
child: OutlinedButton(
style: OutlinedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
side: BorderSide(color: Colors.grey),
),
onPressed: () {
Navigator.pop(context);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.arrow_back, size: 18),
SizedBox(width: 8),
Text("Kembali"),
],
),
),
),
SizedBox(width: 12),
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF25D366),
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 3,
),
onPressed: _kirimWhatsApp,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.phone, size: 20),
SizedBox(width: 8),
Text(
"Kirim via WhatsApp",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
),
),
],
),
SizedBox(height: 40),
],
),
),
);
}
Widget _buildInputField({
required TextEditingController controller,
required String label,
required IconData icon,
required String hint,
bool isPhone = false,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontWeight: FontWeight.w600,
color: Colors.deepOrange,
),
),
SizedBox(height: 8),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 5,
spreadRadius: 1,
),
],
),
child: TextField(
controller: controller,
keyboardType: isPhone ? TextInputType.phone : TextInputType.text,
decoration: InputDecoration(
hintText: hint,
border: InputBorder.none,
prefixIcon: Icon(icon, color: Colors.deepOrange),
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
),
),
),
],
);
}
}
Komentar
Posting Komentar