update total price
This commit is contained in:
parent
013f313e35
commit
0e83d213fc
@ -46,30 +46,33 @@ class CheckoutFormBloc extends Bloc<CheckoutFormEvent, CheckoutFormState> {
|
||||
product: e.product,
|
||||
quantity: 1,
|
||||
variant: e.variant,
|
||||
notes: '',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
log('🛒 Items updated: ${items.length} items total');
|
||||
log('🛒 Items updated: ${items.length} items total ${items.toList()}');
|
||||
|
||||
final totalQuantity = items.fold<int>(
|
||||
0,
|
||||
(sum, item) => sum + item.quantity,
|
||||
);
|
||||
final totalPrice = items.fold<int>(
|
||||
0,
|
||||
(sum, item) =>
|
||||
sum +
|
||||
(item.quantity *
|
||||
(item.variant?.priceModifier.toInt() ??
|
||||
item.product.price.toInt())),
|
||||
);
|
||||
|
||||
final totalPrice = state.items.isEmpty
|
||||
? 0.0
|
||||
: state.items
|
||||
.map(
|
||||
(e) =>
|
||||
(e.product.price * e.quantity) +
|
||||
(e.variant?.priceModifier ?? 0),
|
||||
)
|
||||
.reduce((value, element) => value + element);
|
||||
|
||||
emit(
|
||||
currentState.copyWith(
|
||||
items: items,
|
||||
totalQuantity: totalQuantity,
|
||||
totalPrice: totalPrice,
|
||||
totalPrice: totalPrice.toInt(),
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
|
||||
@ -6,9 +6,9 @@ class ProductQuantity with _$ProductQuantity {
|
||||
required Product product,
|
||||
ProductVariant? variant,
|
||||
required int quantity,
|
||||
String? notes,
|
||||
required String notes,
|
||||
}) = _ProductQuantity;
|
||||
|
||||
factory ProductQuantity.empty() =>
|
||||
ProductQuantity(product: Product.empty(), quantity: 0);
|
||||
ProductQuantity(product: Product.empty(), quantity: 0, notes: '');
|
||||
}
|
||||
|
||||
@ -1097,7 +1097,7 @@ mixin _$ProductQuantity {
|
||||
Product get product => throw _privateConstructorUsedError;
|
||||
ProductVariant? get variant => throw _privateConstructorUsedError;
|
||||
int get quantity => throw _privateConstructorUsedError;
|
||||
String? get notes => throw _privateConstructorUsedError;
|
||||
String get notes => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of ProductQuantity
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@ -1117,7 +1117,7 @@ abstract class $ProductQuantityCopyWith<$Res> {
|
||||
Product product,
|
||||
ProductVariant? variant,
|
||||
int quantity,
|
||||
String? notes,
|
||||
String notes,
|
||||
});
|
||||
|
||||
$ProductCopyWith<$Res> get product;
|
||||
@ -1142,7 +1142,7 @@ class _$ProductQuantityCopyWithImpl<$Res, $Val extends ProductQuantity>
|
||||
Object? product = null,
|
||||
Object? variant = freezed,
|
||||
Object? quantity = null,
|
||||
Object? notes = freezed,
|
||||
Object? notes = null,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
@ -1158,10 +1158,10 @@ class _$ProductQuantityCopyWithImpl<$Res, $Val extends ProductQuantity>
|
||||
? _value.quantity
|
||||
: quantity // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
notes: freezed == notes
|
||||
notes: null == notes
|
||||
? _value.notes
|
||||
: notes // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
as String,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
@ -1205,7 +1205,7 @@ abstract class _$$ProductQuantityImplCopyWith<$Res>
|
||||
Product product,
|
||||
ProductVariant? variant,
|
||||
int quantity,
|
||||
String? notes,
|
||||
String notes,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -1231,7 +1231,7 @@ class __$$ProductQuantityImplCopyWithImpl<$Res>
|
||||
Object? product = null,
|
||||
Object? variant = freezed,
|
||||
Object? quantity = null,
|
||||
Object? notes = freezed,
|
||||
Object? notes = null,
|
||||
}) {
|
||||
return _then(
|
||||
_$ProductQuantityImpl(
|
||||
@ -1247,10 +1247,10 @@ class __$$ProductQuantityImplCopyWithImpl<$Res>
|
||||
? _value.quantity
|
||||
: quantity // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
notes: freezed == notes
|
||||
notes: null == notes
|
||||
? _value.notes
|
||||
: notes // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
as String,
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -1265,7 +1265,7 @@ class _$ProductQuantityImpl
|
||||
required this.product,
|
||||
this.variant,
|
||||
required this.quantity,
|
||||
this.notes,
|
||||
required this.notes,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -1275,7 +1275,7 @@ class _$ProductQuantityImpl
|
||||
@override
|
||||
final int quantity;
|
||||
@override
|
||||
final String? notes;
|
||||
final String notes;
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
@ -1326,7 +1326,7 @@ abstract class _ProductQuantity implements ProductQuantity {
|
||||
required final Product product,
|
||||
final ProductVariant? variant,
|
||||
required final int quantity,
|
||||
final String? notes,
|
||||
required final String notes,
|
||||
}) = _$ProductQuantityImpl;
|
||||
|
||||
@override
|
||||
@ -1336,7 +1336,7 @@ abstract class _ProductQuantity implements ProductQuantity {
|
||||
@override
|
||||
int get quantity;
|
||||
@override
|
||||
String? get notes;
|
||||
String get notes;
|
||||
|
||||
/// Create a copy of ProductQuantity
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../application/auth/auth_bloc.dart';
|
||||
import '../application/category/category_loader/category_loader_bloc.dart';
|
||||
import '../application/checkout/checkout_form/checkout_form_bloc.dart';
|
||||
import '../application/outlet/outlet_loader/outlet_loader_bloc.dart';
|
||||
import '../application/product/product_loader/product_loader_bloc.dart';
|
||||
import '../common/theme/theme.dart';
|
||||
@ -29,6 +30,7 @@ class _AppWidgetState extends State<AppWidget> {
|
||||
BlocProvider(create: (context) => getIt<OutletLoaderBloc>()),
|
||||
BlocProvider(create: (context) => getIt<CategoryLoaderBloc>()),
|
||||
BlocProvider(create: (context) => getIt<ProductLoaderBloc>()),
|
||||
BlocProvider(create: (context) => getIt<CheckoutFormBloc>()),
|
||||
],
|
||||
child: MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
|
||||
156
lib/presentation/components/card/order_menu.dart
Normal file
156
lib/presentation/components/card/order_menu.dart
Normal file
@ -0,0 +1,156 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../application/checkout/checkout_form/checkout_form_bloc.dart';
|
||||
import '../../../common/extension/extension.dart';
|
||||
import '../../../common/theme/theme.dart';
|
||||
import '../../../domain/product/product.dart';
|
||||
import '../image/image.dart';
|
||||
import '../spaces/space.dart';
|
||||
|
||||
class OrderMenu extends StatefulWidget {
|
||||
final ProductQuantity data;
|
||||
const OrderMenu({super.key, required this.data});
|
||||
|
||||
@override
|
||||
State<OrderMenu> createState() => _OrderMenuState();
|
||||
}
|
||||
|
||||
class _OrderMenuState extends State<OrderMenu> {
|
||||
final _controller = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller.text = widget.data.notes;
|
||||
|
||||
_controller.addListener(() {
|
||||
context.read<CheckoutFormBloc>().add(
|
||||
CheckoutFormEvent.updateItemNotes(
|
||||
widget.data.product,
|
||||
_controller.text,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||
child: AppNetworkImage(
|
||||
url: widget.data.product.imageUrl,
|
||||
width: 50.0,
|
||||
height: 50.0,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.data.product.name,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
(widget.data.product.price +
|
||||
(widget.data.variant?.priceModifier ?? 0))
|
||||
.currencyFormatRp,
|
||||
),
|
||||
if (widget.data.variant != null)
|
||||
Text(widget.data.variant?.name ?? ""),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CheckoutFormBloc>().add(
|
||||
CheckoutFormEvent.removeItem(
|
||||
widget.data.product,
|
||||
widget.data.variant,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
color: AppColor.white,
|
||||
child: const Icon(
|
||||
Icons.remove_circle,
|
||||
color: AppColor.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 30.0,
|
||||
child: Center(child: Text(widget.data.quantity.toString())),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CheckoutFormBloc>().add(
|
||||
CheckoutFormEvent.addItem(
|
||||
widget.data.product,
|
||||
widget.data.variant,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
color: AppColor.white,
|
||||
child: const Icon(
|
||||
Icons.add_circle,
|
||||
color: AppColor.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SpaceWidth(8),
|
||||
SizedBox(
|
||||
width: 80.0,
|
||||
child: Text(
|
||||
((widget.data.product.price +
|
||||
(widget.data.variant?.priceModifier ?? 0)) *
|
||||
widget.data.quantity)
|
||||
.currencyFormatRp,
|
||||
textAlign: TextAlign.right,
|
||||
style: const TextStyle(
|
||||
color: AppColor.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../application/checkout/checkout_form/checkout_form_bloc.dart';
|
||||
import '../../../common/extension/extension.dart';
|
||||
import '../../../common/theme/theme.dart';
|
||||
import '../../../domain/product/product.dart';
|
||||
@ -17,9 +19,9 @@ class ProductCard extends StatelessWidget {
|
||||
onTap: () {
|
||||
if (product.isActive == true) {
|
||||
if (product.variants.isEmpty) {
|
||||
// context.read<CheckoutBloc>().add(
|
||||
// CheckoutEvent.addItem(data, null),
|
||||
// );
|
||||
context.read<CheckoutFormBloc>().add(
|
||||
CheckoutFormEvent.addItem(product, null),
|
||||
);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
@ -85,28 +87,40 @@ class ProductCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
|
||||
Positioned(
|
||||
top: 4,
|
||||
right: 4,
|
||||
child: Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(9.0)),
|
||||
color: AppColor.primary,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
0.toString(),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
BlocBuilder<CheckoutFormBloc, CheckoutFormState>(
|
||||
builder: (context, state) {
|
||||
final totalQuantity = state.items
|
||||
.where((item) => item.product.id == product.id)
|
||||
.map((item) => item.quantity)
|
||||
.fold(0, (sum, qty) => sum + qty);
|
||||
|
||||
if (totalQuantity == 0) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Positioned(
|
||||
top: 4,
|
||||
right: 4,
|
||||
child: Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(9.0)),
|
||||
color: AppColor.primary,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
totalQuantity.toString(),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
if (product.isActive == false)
|
||||
Container(
|
||||
|
||||
@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../application/checkout/checkout_form/checkout_form_bloc.dart';
|
||||
import '../../../application/outlet/outlet_loader/outlet_loader_bloc.dart';
|
||||
import '../../../common/extension/extension.dart';
|
||||
import '../../../common/theme/theme.dart';
|
||||
|
||||
@ -21,10 +21,10 @@ class VariantDialog extends StatelessWidget {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
// Aksi saat varian dipilih
|
||||
// context.pop();
|
||||
// context.read<CheckoutBloc>().add(
|
||||
// CheckoutEvent.addItem(product, variant),
|
||||
// );
|
||||
context.maybePop();
|
||||
context.read<CheckoutFormBloc>().add(
|
||||
CheckoutFormEvent.addItem(product, variant),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: (context.deviceWidth * 0.4 - 12 - 32) / 2 - 6, // 2 per row
|
||||
|
||||
@ -1,6 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../../../../application/checkout/checkout_form/checkout_form_bloc.dart';
|
||||
import '../../../../../../common/extension/extension.dart';
|
||||
import '../../../../../../common/theme/theme.dart';
|
||||
import '../../../../../components/button/button.dart';
|
||||
import '../../../../../components/card/order_menu.dart';
|
||||
import '../../../../../components/spaces/space.dart';
|
||||
import '../../../../../components/toast/flushbar.dart';
|
||||
import 'home_right_title.dart';
|
||||
|
||||
class HomeRightPanel extends StatelessWidget {
|
||||
@ -8,12 +17,168 @@ class HomeRightPanel extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
child: Column(children: [HomeRightTitle()]),
|
||||
),
|
||||
return BlocBuilder<CheckoutFormBloc, CheckoutFormState>(
|
||||
builder: (context, state) {
|
||||
final price = state.items.isEmpty
|
||||
? 0.0
|
||||
: state.items
|
||||
.map(
|
||||
(e) =>
|
||||
(e.product.price + (e.variant?.priceModifier ?? 0)) *
|
||||
e.quantity,
|
||||
)
|
||||
.reduce((value, element) => value + element);
|
||||
log('🛒 Total Price: $price');
|
||||
return Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
child: Column(
|
||||
children: [
|
||||
HomeRightTitle(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(
|
||||
16.0,
|
||||
).copyWith(bottom: 0, top: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Item',
|
||||
style: AppStyle.lg.copyWith(
|
||||
color: AppColor.primary,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 130),
|
||||
SizedBox(
|
||||
width: 50.0,
|
||||
child: Text(
|
||||
'Qty',
|
||||
style: AppStyle.lg.copyWith(
|
||||
color: AppColor.primary,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
child: Text(
|
||||
'Price',
|
||||
style: AppStyle.lg.copyWith(
|
||||
color: AppColor.primary,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SpaceHeight(8),
|
||||
const Divider(),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: state.items.isEmpty
|
||||
? const Center(child: Text('No Items'))
|
||||
: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
itemBuilder: (context, index) =>
|
||||
OrderMenu(data: state.items[index]),
|
||||
separatorBuilder: (context, index) =>
|
||||
const SpaceHeight(1.0),
|
||||
itemCount: state.items.length,
|
||||
),
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0).copyWith(top: 0),
|
||||
child: Column(
|
||||
children: [
|
||||
const Divider(),
|
||||
const SpaceHeight(16.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Pajak',
|
||||
style: AppStyle.md.copyWith(
|
||||
color: AppColor.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${state.tax} %',
|
||||
style: AppStyle.md.copyWith(
|
||||
color: AppColor.primary,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SpaceHeight(16.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Sub total',
|
||||
style: TextStyle(
|
||||
color: AppColor.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
price.currencyFormatRp,
|
||||
style: const TextStyle(
|
||||
color: AppColor.primary,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SpaceHeight(16.0),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: AppElevatedButton.filled(
|
||||
borderRadius: 12,
|
||||
elevation: 1,
|
||||
disabled: state.items.isEmpty,
|
||||
onPressed: () {
|
||||
if (state.orderType.name == 'dineIn') {
|
||||
AppFlushbar.showError(
|
||||
context,
|
||||
'Mohon pilih meja terlebih dahulu',
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (state.orderType.name == 'delivery' &&
|
||||
state.delivery == null) {
|
||||
AppFlushbar.showError(
|
||||
context,
|
||||
'Mohon pilih pengiriman terlebih dahulu',
|
||||
);
|
||||
return;
|
||||
}
|
||||
// context.push(
|
||||
// ConfirmPaymentPage(
|
||||
// isTable: widget.table == null ? false : true,
|
||||
// table: widget.table,
|
||||
// ),
|
||||
// );
|
||||
},
|
||||
label: 'Lanjutkan Pembayaran',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user