6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit ee530a82
Changed files
.../presentation/app/cart_cubit.freezed.dart | 46 +++++++++-------- .../product_details/product_details_route.g.dart | 34 ++++++++++++- concierge/lib/domain/models/delivery_method.dart | 17 +++++++ concierge/lib/domain/models/product_in_cart.dart | 7 +++ concierge/lib/presentation/app/cart_cubit.dart | 23 ++++++--- .../product_details/product_details_route.dart | 8 ++- .../widgets/product_details_app_bar.dart | 1 - .../screens/review_order/review_order_screen.dart | 57 +++++++++++++++------- .../widget/delivery_method_picker.dart | 41 ++++++++++++++++ .../widget/product_in_cart_list_tile.dart | 45 +++++++++++++++++ .../review_order/widget/review_order_app_bar.dart | 39 +++++++++++++++ 11 files changed, 268 insertions(+), 50 deletions(-)
Diff
diff --git a/concierge/lib/_generated/presentation/app/cart_cubit.freezed.dart b/concierge/lib/_generated/presentation/app/cart_cubit.freezed.dart
index 0a84501c..94ad16eb 100644
--- a/concierge/lib/_generated/presentation/app/cart_cubit.freezed.dart
+++ b/concierge/lib/_generated/presentation/app/cart_cubit.freezed.dart
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$CartState {
- bool get isLoading; AppError get error; Map<int, ProductInCart> get productsWithQuantity;
+ bool get isLoading; AppError get error; Map<int, ProductInCart> get productsWithQuantity; DeliveryMethod get deliveryMethod; String get comment;
/// Create a copy of CartState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -25,16 +25,16 @@ $CartStateCopyWith<CartState> get copyWith => _$CartStateCopyWithImpl<CartState>
@override
bool operator ==(Object other) {
- return identical(this, other) || (other.runtimeType == runtimeType&&other is CartState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&const DeepCollectionEquality().equals(other.productsWithQuantity, productsWithQuantity));
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is CartState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&const DeepCollectionEquality().equals(other.productsWithQuantity, productsWithQuantity)&&(identical(other.deliveryMethod, deliveryMethod) || other.deliveryMethod == deliveryMethod)&&(identical(other.comment, comment) || other.comment == comment));
}
@override
-int get hashCode => Object.hash(runtimeType,isLoading,error,const DeepCollectionEquality().hash(productsWithQuantity));
+int get hashCode => Object.hash(runtimeType,isLoading,error,const DeepCollectionEquality().hash(productsWithQuantity),deliveryMethod,comment);
@override
String toString() {
- return 'CartState(isLoading: $isLoading, error: $error, productsWithQuantity: $productsWithQuantity)';
+ return 'CartState(isLoading: $isLoading, error: $error, productsWithQuantity: $productsWithQuantity, deliveryMethod: $deliveryMethod, comment: $comment)';
}
@@ -45,7 +45,7 @@ abstract mixin class $CartStateCopyWith<$Res> {
factory $CartStateCopyWith(CartState value, $Res Function(CartState) _then) = _$CartStateCopyWithImpl;
@useResult
$Res call({
- bool isLoading, AppError error, Map<int, ProductInCart> productsWithQuantity
+ bool isLoading, AppError error, Map<int, ProductInCart> productsWithQuantity, DeliveryMethod deliveryMethod, String comment
});
@@ -62,12 +62,14 @@ class _$CartStateCopyWithImpl<$Res>
/// Create a copy of CartState
/// with the given fields replaced by the non-null parameter values.
-@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? error = null,Object? productsWithQuantity = null,}) {
+@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? error = null,Object? productsWithQuantity = null,Object? deliveryMethod = null,Object? comment = null,}) {
return _then(_self.copyWith(
isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
as AppError,productsWithQuantity: null == productsWithQuantity ? _self.productsWithQuantity : productsWithQuantity // ignore: cast_nullable_to_non_nullable
-as Map<int, ProductInCart>,
+as Map<int, ProductInCart>,deliveryMethod: null == deliveryMethod ? _self.deliveryMethod : deliveryMethod // ignore: cast_nullable_to_non_nullable
+as DeliveryMethod,comment: null == comment ? _self.comment : comment // ignore: cast_nullable_to_non_nullable
+as String,
));
}
@@ -152,10 +154,10 @@ return $default(_that);case _:
/// }
/// ```
-@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, AppError error, Map<int, ProductInCart> productsWithQuantity)? $default,{required TResult orElse(),}) {final _that = this;
+@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, AppError error, Map<int, ProductInCart> productsWithQuantity, DeliveryMethod deliveryMethod, String comment)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _CartState() when $default != null:
-return $default(_that.isLoading,_that.error,_that.productsWithQuantity);case _:
+return $default(_that.isLoading,_that.error,_that.productsWithQuantity,_that.deliveryMethod,_that.comment);case _:
return orElse();
}
@@ -173,10 +175,10 @@ return $default(_that.isLoading,_that.error,_that.productsWithQuantity);case _:
/// }
/// ```
-@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, AppError error, Map<int, ProductInCart> productsWithQuantity) $default,) {final _that = this;
+@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, AppError error, Map<int, ProductInCart> productsWithQuantity, DeliveryMethod deliveryMethod, String comment) $default,) {final _that = this;
switch (_that) {
case _CartState():
-return $default(_that.isLoading,_that.error,_that.productsWithQuantity);case _:
+return $default(_that.isLoading,_that.error,_that.productsWithQuantity,_that.deliveryMethod,_that.comment);case _:
throw StateError('Unexpected subclass');
}
@@ -193,10 +195,10 @@ return $default(_that.isLoading,_that.error,_that.productsWithQuantity);case _:
/// }
/// ```
-@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, AppError error, Map<int, ProductInCart> productsWithQuantity)? $default,) {final _that = this;
+@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, AppError error, Map<int, ProductInCart> productsWithQuantity, DeliveryMethod deliveryMethod, String comment)? $default,) {final _that = this;
switch (_that) {
case _CartState() when $default != null:
-return $default(_that.isLoading,_that.error,_that.productsWithQuantity);case _:
+return $default(_that.isLoading,_that.error,_that.productsWithQuantity,_that.deliveryMethod,_that.comment);case _:
return null;
}
@@ -208,7 +210,7 @@ return $default(_that.isLoading,_that.error,_that.productsWithQuantity);case _:
class _CartState extends CartState {
- const _CartState({this.isLoading = false, this.error = AppError.none, final Map<int, ProductInCart> productsWithQuantity = const {}}): _productsWithQuantity = productsWithQuantity,super._();
+ const _CartState({this.isLoading = false, this.error = AppError.none, final Map<int, ProductInCart> productsWithQuantity = const {}, this.deliveryMethod = DeliveryMethod.pickUp, this.comment = ""}): _productsWithQuantity = productsWithQuantity,super._();
@override@JsonKey() final bool isLoading;
@@ -220,6 +222,8 @@ class _CartState extends CartState {
return EqualUnmodifiableMapView(_productsWithQuantity);
}
+@override@JsonKey() final DeliveryMethod deliveryMethod;
+@override@JsonKey() final String comment;
/// Create a copy of CartState
/// with the given fields replaced by the non-null parameter values.
@@ -231,16 +235,16 @@ _$CartStateCopyWith<_CartState> get copyWith => __$CartStateCopyWithImpl<_CartSt
@override
bool operator ==(Object other) {
- return identical(this, other) || (other.runtimeType == runtimeType&&other is _CartState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&const DeepCollectionEquality().equals(other._productsWithQuantity, _productsWithQuantity));
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _CartState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error)&&const DeepCollectionEquality().equals(other._productsWithQuantity, _productsWithQuantity)&&(identical(other.deliveryMethod, deliveryMethod) || other.deliveryMethod == deliveryMethod)&&(identical(other.comment, comment) || other.comment == comment));
}
@override
-int get hashCode => Object.hash(runtimeType,isLoading,error,const DeepCollectionEquality().hash(_productsWithQuantity));
+int get hashCode => Object.hash(runtimeType,isLoading,error,const DeepCollectionEquality().hash(_productsWithQuantity),deliveryMethod,comment);
@override
String toString() {
- return 'CartState(isLoading: $isLoading, error: $error, productsWithQuantity: $productsWithQuantity)';
+ return 'CartState(isLoading: $isLoading, error: $error, productsWithQuantity: $productsWithQuantity, deliveryMethod: $deliveryMethod, comment: $comment)';
}
@@ -251,7 +255,7 @@ abstract mixin class _$CartStateCopyWith<$Res> implements $CartStateCopyWith<$Re
factory _$CartStateCopyWith(_CartState value, $Res Function(_CartState) _then) = __$CartStateCopyWithImpl;
@override @useResult
$Res call({
- bool isLoading, AppError error, Map<int, ProductInCart> productsWithQuantity
+ bool isLoading, AppError error, Map<int, ProductInCart> productsWithQuantity, DeliveryMethod deliveryMethod, String comment
});
@@ -268,12 +272,14 @@ class __$CartStateCopyWithImpl<$Res>
/// Create a copy of CartState
/// with the given fields replaced by the non-null parameter values.
-@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? error = null,Object? productsWithQuantity = null,}) {
+@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? error = null,Object? productsWithQuantity = null,Object? deliveryMethod = null,Object? comment = null,}) {
return _then(_CartState(
isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
as AppError,productsWithQuantity: null == productsWithQuantity ? _self._productsWithQuantity : productsWithQuantity // ignore: cast_nullable_to_non_nullable
-as Map<int, ProductInCart>,
+as Map<int, ProductInCart>,deliveryMethod: null == deliveryMethod ? _self.deliveryMethod : deliveryMethod // ignore: cast_nullable_to_non_nullable
+as DeliveryMethod,comment: null == comment ? _self.comment : comment // ignore: cast_nullable_to_non_nullable
+as String,
));
}
diff --git a/concierge/lib/_generated/presentation/screens/product_details/product_details_route.g.dart b/concierge/lib/_generated/presentation/screens/product_details/product_details_route.g.dart
index 0b14509e..e4941918 100644
--- a/concierge/lib/_generated/presentation/screens/product_details/product_details_route.g.dart
+++ b/concierge/lib/_generated/presentation/screens/product_details/product_details_route.g.dart
@@ -15,13 +15,25 @@ RouteBase get $productDetailsRoute => GoRouteData.$route(
mixin $ProductDetailsRoute on GoRouteData {
static ProductDetailsRoute _fromState(GoRouterState state) =>
- ProductDetailsRoute(int.parse(state.pathParameters['id']!));
+ ProductDetailsRoute(
+ int.parse(state.pathParameters['id']!),
+ isEdit:
+ _$convertMapValue(
+ 'is-edit',
+ state.uri.queryParameters,
+ _$boolConverter,
+ ) ??
+ false,
+ );
ProductDetailsRoute get _self => this as ProductDetailsRoute;
@override
String get location => GoRouteData.$location(
'/concierge/products/${Uri.encodeComponent(_self.id.toString())}',
+ queryParams: {
+ if (_self.isEdit != false) 'is-edit': _self.isEdit.toString(),
+ },
);
@override
@@ -37,3 +49,23 @@ mixin $ProductDetailsRoute on GoRouteData {
@override
void replace(BuildContext context) => context.replace(location);
}
+
+T? _$convertMapValue<T>(
+ String key,
+ Map<String, String> map,
+ T? Function(String) converter,
+) {
+ final value = map[key];
+ return value == null ? null : converter(value);
+}
+
+bool _$boolConverter(String value) {
+ switch (value) {
+ case 'true':
+ return true;
+ case 'false':
+ return false;
+ default:
+ throw UnsupportedError('Cannot convert "$value" into a bool.');
+ }
+}
diff --git a/concierge/lib/domain/models/delivery_method.dart b/concierge/lib/domain/models/delivery_method.dart
new file mode 100644
index 00000000..90efd3d9
--- /dev/null
+++ b/concierge/lib/domain/models/delivery_method.dart
@@ -0,0 +1,17 @@
+sealed class DeliveryMethod {
+ const DeliveryMethod();
+
+ static const pickUp = PickUp();
+
+ static delivery(String time) => Delivery(time);
+}
+
+class PickUp extends DeliveryMethod {
+ const PickUp();
+}
+
+class Delivery extends DeliveryMethod {
+ final String time;
+
+ const Delivery(this.time);
+}
diff --git a/concierge/lib/domain/models/product_in_cart.dart b/concierge/lib/domain/models/product_in_cart.dart
new file mode 100644
index 00000000..a13da826
--- /dev/null
+++ b/concierge/lib/domain/models/product_in_cart.dart
@@ -0,0 +1,7 @@
+class ProductInCart {
+ final int productId;
+ final Map<int, int> variant; // option-answer pairs
+ final int quantity;
+
+ ProductInCart(this.productId, this.variant, this.quantity);
+}
diff --git a/concierge/lib/presentation/app/cart_cubit.dart b/concierge/lib/presentation/app/cart_cubit.dart
index 7acd1191..5e72e5f1 100644
--- a/concierge/lib/presentation/app/cart_cubit.dart
+++ b/concierge/lib/presentation/app/cart_cubit.dart
@@ -1,10 +1,13 @@
import 'package:concierge/data/remote/models/product.dart';
import 'package:concierge/domain/models/data_state.dart';
+import 'package:concierge/domain/models/delivery_method.dart';
import 'package:concierge/presentation/app/concierge_cubit.dart';
import 'package:concierge/presentation/base/base_cubit.dart';
import 'package:concierge/domain/models/app_error.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
+import '../../domain/models/product_in_cart.dart';
+
part '../../_generated/presentation/app/cart_cubit.freezed.dart';
class CartCubit extends BaseCubit<CartState> {
@@ -20,6 +23,16 @@ class CartCubit extends BaseCubit<CartState> {
ProductInCart? getProduct(int productId) => state.productsWithQuantity[productId];
+ int getQuantity(int productId) => state.productsWithQuantity[productId]?.quantity ?? 0;
+
+ void updateComment(String comment) {
+ safeEmit(state.copyWith(comment: comment));
+ }
+
+ void updateDelivery(DeliveryMethod deliveryMethod) {
+ safeEmit(state.copyWith(deliveryMethod: deliveryMethod));
+ }
+
int get totalItems {
if (state.productsWithQuantity.isEmpty) return 0;
return state.productsWithQuantity.values
@@ -50,15 +63,9 @@ abstract class CartState with _$CartState {
@Default(false) bool isLoading,
@Default(AppError.none) AppError error,
@Default({}) Map<int, ProductInCart> productsWithQuantity,
+ @Default(DeliveryMethod.pickUp) DeliveryMethod deliveryMethod,
+ @Default("") String comment,
}) = _CartState;
const CartState._();
}
-
-class ProductInCart {
- final int productId;
- final Map<int, int> variant;
- final int quantity;
-
- ProductInCart(this.productId, this.variant, this.quantity);
-}
diff --git a/concierge/lib/presentation/screens/product_details/product_details_route.dart b/concierge/lib/presentation/screens/product_details/product_details_route.dart
index d02a91a5..be60c1f9 100644
--- a/concierge/lib/presentation/screens/product_details/product_details_route.dart
+++ b/concierge/lib/presentation/screens/product_details/product_details_route.dart
@@ -20,8 +20,12 @@ class ProductDetailsRoute extends GoRouteData with $ProductDetailsRoute {
return slideInTransition(
state: state,
child: BlocProvider(
- create: (context) =>
- ProductDetailsCubit(context.read(), context.read(), productId: id, isEdit: isEdit),
+ create: (context) => ProductDetailsCubit(
+ context.read(),
+ context.read(),
+ productId: id,
+ isEdit: isEdit,
+ ),
child: ProductDetailsScreen(),
),
);
diff --git a/concierge/lib/presentation/screens/product_details/widgets/product_details_app_bar.dart b/concierge/lib/presentation/screens/product_details/widgets/product_details_app_bar.dart
index 5037378a..c09fa2f8 100644
--- a/concierge/lib/presentation/screens/product_details/widgets/product_details_app_bar.dart
+++ b/concierge/lib/presentation/screens/product_details/widgets/product_details_app_bar.dart
@@ -11,7 +11,6 @@ class ProductDetailsAppBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final cartCubit = context.watch<CartCubit>();
final productDetailsCubit = context.read<ProductDetailsCubit>();
final state = productDetailsCubit.state;
return Padding(
diff --git a/concierge/lib/presentation/screens/review_order/review_order_screen.dart b/concierge/lib/presentation/screens/review_order/review_order_screen.dart
index 6521a64e..378a9a96 100644
--- a/concierge/lib/presentation/screens/review_order/review_order_screen.dart
+++ b/concierge/lib/presentation/screens/review_order/review_order_screen.dart
@@ -1,41 +1,62 @@
-import 'package:concierge/presentation/screens/provide_location/provide_location_route.dart';
+import 'package:concierge/data/remote/models/product.dart';
+import 'package:concierge/presentation/app/cart_cubit.dart';
+import 'package:concierge/presentation/screens/review_order/widget/delivery_method_picker.dart';
+import 'package:concierge/presentation/screens/review_order/widget/product_in_cart_list_tile.dart';
+import 'package:concierge/presentation/screens/review_order/widget/review_order_app_bar.dart';
+import 'package:concierge/presentation/widgets/padded_column.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:concierge/presentation/screens/review_order/bloc/review_order_cubit.dart';
import 'package:concierge/presentation/screens/review_order/bloc/review_order_state.dart';
+import 'package:gap/gap.dart';
class ReviewOrderScreen extends StatelessWidget {
const ReviewOrderScreen({super.key});
@override
Widget build(BuildContext context) {
+ final cartCubit = context.watch<CartCubit>();
+ final cubit = context.read<ReviewOrderCubit>();
return BlocBuilder<ReviewOrderCubit, ReviewOrderState>(
builder: (context, state) {
- final cubit = context.read<ReviewOrderCubit>();
return MultiBlocListener(
listeners: [
BlocListener<ReviewOrderCubit, ReviewOrderState>(
- listenWhen: (prev, curr) =>
- prev.isLoading && curr.error.isError,
- listener: (context, state) {
- },
- )
+ listenWhen: (prev, curr) => prev.isLoading && curr.error.isError,
+ listener: (context, state) {},
+ ),
],
child: Scaffold(
appBar: AppBar(),
- body: Center(
- child: Column(
- children: [
- Text("ReviewOrder"),
- TextButton(onPressed: () {
- ProvideLocationRoute().push(context);
- }, child: Text("Angiv lokation"))
- ],
- ),
+ bottomNavigationBar: ReviewOrderAppBar(),
+ body: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text("ReviewOrder"),
+ const DeliveryMethodPicker(),
+ PaddedColumn(
+ padding: EdgeInsets.symmetric(horizontal: 16),
+ children: buildProducts(context, cartCubit.products).toList(),
+ ),
+ Gap(16),
+ Text("Kommentar til ordre"),
+ TextField(),
+ ],
),
),
);
},
);
- }
-}
\ No newline at end of file
+ }
+
+ Iterable<Widget> buildProducts(BuildContext context, Iterable<Product> products) sync* {
+ yield Divider();
+ for (final product in products) {
+ Gap(12);
+ yield ProductInCartListTile(product: product);
+ Gap(12);
+ yield Divider();
+ }
+ }
+}
diff --git a/concierge/lib/presentation/screens/review_order/widget/delivery_method_picker.dart b/concierge/lib/presentation/screens/review_order/widget/delivery_method_picker.dart
new file mode 100644
index 00000000..3077bd8e
--- /dev/null
+++ b/concierge/lib/presentation/screens/review_order/widget/delivery_method_picker.dart
@@ -0,0 +1,41 @@
+import 'package:concierge/domain/models/delivery_method.dart';
+import 'package:concierge/presentation/app/cart_cubit.dart';
+import 'package:concierge/presentation/theme/app_colors.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class DeliveryMethodPicker extends StatelessWidget {
+ const DeliveryMethodPicker({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final cartCubit = context.watch<CartCubit>();
+ return Row(
+ children: [
+ TextButton(
+ onPressed: () {
+ cartCubit.updateDelivery(DeliveryMethod.delivery("16:00"));
+ },
+ child: Text(
+ "Levering",
+ style: TextStyle(
+ color: cartCubit.state.deliveryMethod is Delivery ? AppColors.sandColor : null,
+ ),
+ ),
+ ),
+ Spacer(),
+ TextButton(
+ onPressed: () {
+ cartCubit.updateDelivery(DeliveryMethod.pickUp);
+ },
+ child: Text(
+ "Afhentning",
+ style: TextStyle(
+ color: cartCubit.state.deliveryMethod is PickUp ? AppColors.sandColor : null,
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/concierge/lib/presentation/screens/review_order/widget/product_in_cart_list_tile.dart b/concierge/lib/presentation/screens/review_order/widget/product_in_cart_list_tile.dart
new file mode 100644
index 00000000..d73d1c3f
--- /dev/null
+++ b/concierge/lib/presentation/screens/review_order/widget/product_in_cart_list_tile.dart
@@ -0,0 +1,45 @@
+import 'package:concierge/data/remote/models/product.dart';
+import 'package:concierge/presentation/app/cart_cubit.dart';
+import 'package:concierge/presentation/screens/product_details/product_details_route.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class ProductInCartListTile extends StatelessWidget {
+ const ProductInCartListTile({super.key, required this.product});
+
+ final Product product;
+
+ @override
+ Widget build(BuildContext context) {
+ final cartCubit = context.read<CartCubit>();
+ final quantity = cartCubit.getQuantity(product.id);
+ final price = product.price * quantity;
+
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Image.network(
+ product.images.first.url,
+ height: 80,
+ width: 80,
+ ),
+ Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text("${quantity}x${product.title}"),
+ Text("$price kr."),
+ ],
+ ),
+ TextButton(
+ onPressed: () {
+ ProductDetailsRoute(product.id, isEdit: true).push(context);
+ },
+ child: Text("Rediger"),
+ ),
+ ],
+ );
+ }
+}
diff --git a/concierge/lib/presentation/screens/review_order/widget/review_order_app_bar.dart b/concierge/lib/presentation/screens/review_order/widget/review_order_app_bar.dart
new file mode 100644
index 00000000..b340a9cb
--- /dev/null
+++ b/concierge/lib/presentation/screens/review_order/widget/review_order_app_bar.dart
@@ -0,0 +1,39 @@
+import 'package:concierge/presentation/app/cart_cubit.dart';
+import 'package:concierge/presentation/screens/provide_location/provide_location_route.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class ReviewOrderAppBar extends StatelessWidget {
+ const ReviewOrderAppBar({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final cartCubit = context.read<CartCubit>();
+ return Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Container(
+ height: 100,
+ child: SafeArea(
+ child: ElevatedButton(
+ onPressed: () {
+ ProvideLocationRoute().push(context);
+ },
+ child: Row(
+ children: [
+ Text(
+ "Bekræft bestilling",
+ style: TextStyle(color: Colors.white),
+ ),
+ Spacer(),
+ Text(
+ "${cartCubit.totalPrice} kr.",
+ style: TextStyle(color: Colors.white),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}