feat: order card

This commit is contained in:
efrilm 2025-08-29 20:45:42 +07:00
parent 0afb683045
commit 936875c30a
2 changed files with 50 additions and 255 deletions

View File

@ -144,7 +144,6 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: AppColor.background,
appBar: _buildAppBar(), appBar: _buildAppBar(),
body: Column( body: Column(
children: [ children: [

View File

@ -15,271 +15,80 @@ class OrderCard extends StatelessWidget {
return GestureDetector( return GestureDetector(
onTap: () => context.router.push(OrderDetailRoute(order: order)), onTap: () => context.router.push(OrderDetailRoute(order: order)),
child: Container( child: Container(
margin: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 0),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColor.white, border: Border(
borderRadius: BorderRadius.circular(16), bottom: BorderSide(
boxShadow: [ color: AppColor.border.withOpacity(0.3),
BoxShadow( width: 1,
color: AppColor.black.withOpacity(0.06),
blurRadius: 16,
offset: const Offset(0, 3),
),
],
),
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
children: [
_buildHeader(),
const SizedBox(height: 16),
_buildContent(),
const SizedBox(height: 16),
_buildFooter(),
],
),
),
),
);
}
Widget _buildHeader() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: AppColor.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
order.id,
style: AppStyle.sm.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.primary,
),
),
),
],
),
const SizedBox(height: 6),
Text(
DateFormat('dd MMM yyyy • HH:mm').format(order.orderDate),
style: AppStyle.sm.copyWith(color: AppColor.textSecondary),
),
],
),
),
_buildStatusChip(),
],
);
}
Widget _buildStatusChip() {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
decoration: BoxDecoration(
color: _getStatusColor().withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: _getStatusColor().withOpacity(0.2), width: 1),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(_getStatusIcon(), size: 12, color: _getStatusColor()),
const SizedBox(width: 6),
Text(
_getStatusText(),
style: AppStyle.sm.copyWith(
color: _getStatusColor(),
fontWeight: FontWeight.w600,
), ),
), ),
], ),
), child: Row(
); children: [
} // Left side - Order info
Expanded(
Widget _buildContent() { child: Column(
return Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: AppColor.background,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.restaurant_menu_outlined,
size: 16,
color: AppColor.textSecondary,
),
const SizedBox(width: 6),
Text(
'${order.items.length} item pesanan',
style: AppStyle.sm.copyWith(
fontWeight: FontWeight.w500,
color: AppColor.textSecondary,
),
),
],
),
const SizedBox(height: 10),
...order.items
.take(3)
.map(
(item) => Container(
margin: const EdgeInsets.only(bottom: 6),
child: Row(
children: [
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: AppColor.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Text(
'${item.quantity}',
style: AppStyle.xs.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.primary,
),
),
),
),
const SizedBox(width: 10),
Expanded(
child: Text(
item.name,
style: AppStyle.sm.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w500,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
Text(
'Rp ${_formatCurrency(item.price * item.quantity)}',
style: AppStyle.sm.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
if (order.items.length > 3) ...[
Container(
margin: const EdgeInsets.only(top: 4),
child: Text(
'+${order.items.length - 3} item lainnya',
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontStyle: FontStyle.italic,
),
),
),
],
if (order.notes != null) ...[
const SizedBox(height: 10),
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: AppColor.warning.withOpacity(0.05),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.warning.withOpacity(0.2)),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Icon( // Order ID
Icons.sticky_note_2_outlined, Text(
size: 14, order.id,
color: AppColor.warning, style: AppStyle.md.copyWith(
), fontWeight: FontWeight.w600,
const SizedBox(width: 6), color: AppColor.textPrimary,
Expanded(
child: Text(
order.notes!,
style: AppStyle.xs.copyWith(
color: AppColor.textPrimary,
height: 1.3,
),
), ),
), ),
const SizedBox(height: 4),
// Order Date
Text(
DateFormat('dd MMM yyyy • HH:mm').format(order.orderDate),
style: AppStyle.sm.copyWith(color: AppColor.textSecondary),
),
], ],
), ),
), ),
],
],
),
);
}
Widget _buildFooter() { // Right side - Status and Total
return Column(
children: [
Container(
height: 1,
width: double.infinity,
color: AppColor.border.withOpacity(0.3),
),
const SizedBox(height: 12),
Row(
children: [
Icon(
order.address != null
? Icons.location_on_outlined
: Icons.store_outlined,
size: 16,
color: AppColor.textSecondary,
),
const SizedBox(width: 6),
Expanded(
child: Text(
order.address ?? 'Ambil di tempat',
style: AppStyle.sm.copyWith(color: AppColor.textSecondary),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 12),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Text( // Status
'Total', Container(
style: AppStyle.xs.copyWith(color: AppColor.textSecondary), padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: _getStatusColor().withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: _getStatusColor().withOpacity(0.2),
width: 1,
),
),
child: Text(
_getStatusText(),
style: AppStyle.xs.copyWith(
color: _getStatusColor(),
fontWeight: FontWeight.w600,
),
),
), ),
const SizedBox(height: 6),
// Total Amount
Text( Text(
'Rp ${_formatCurrency(order.totalAmount)}', 'Rp ${_formatCurrency(order.totalAmount)}',
style: AppStyle.lg.copyWith( style: AppStyle.md.copyWith(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
color: AppColor.primary, color: AppColor.textPrimary,
), ),
), ),
], ],
), ),
], ],
), ),
], ),
); );
} }
@ -309,19 +118,6 @@ class OrderCard extends StatelessWidget {
} }
} }
IconData _getStatusIcon() {
switch (order.status) {
case OrderStatus.pending:
return Icons.schedule;
case OrderStatus.processing:
return Icons.hourglass_empty;
case OrderStatus.completed:
return Icons.check_circle;
case OrderStatus.cancelled:
return Icons.cancel;
}
}
String _formatCurrency(double amount) { String _formatCurrency(double amount) {
final formatter = NumberFormat('#,###'); final formatter = NumberFormat('#,###');
return formatter.format(amount); return formatter.format(amount);