6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit 78be7e8f

AuthorMikkel Thygesen<mikkelet@gmail.com>
Date2026-03-11 09:46:42 +0100
Concierge payment: Implemented payment page

Changed files

common/pubspec.lock                                |  8 ++++
 common/pubspec.yaml                                |  1 +
 common/scripts/dart/sync_translations.dart         |  2 +-
 .../lib/_generated/data/remote/models/order.g.dart |  2 +-
 .../payment/bloc/payment_state.freezed.dart        | 42 +++++++++--------
 .../receipt/bloc/receipt_state.freezed.dart        | 49 ++++++++++++--------
 .../screens/receipt/receipt_route.g.dart           | 10 +++-
 concierge/lib/concierge_route.dart                 | 21 +++++----
 .../lib/data/remote/api/concierge_service.dart     |  2 +-
 concierge/lib/data/remote/models/order.dart        |  2 +-
 .../domain/repositories/property_repository.dart   |  4 +-
 concierge/lib/flavors.dart                         |  2 +-
 .../confirm_order/confirm_order_screen.dart        |  9 +++-
 .../widgets/confirm_order_product_list_tile.dart   | 19 ++++----
 .../screens/payment/bloc/payment_cubit.dart        | 33 ++++++++++++--
 .../screens/payment/bloc/payment_state.dart        |  2 +
 .../screens/payment/payment_route.dart             | 21 ++++++---
 .../screens/payment/payment_screen.dart            | 53 +++++++++++-----------
 .../screens/receipt/bloc/receipt_cubit.dart        | 49 ++++++++------------
 .../screens/receipt/bloc/receipt_state.dart        |  4 +-
 .../screens/receipt/receipt_route.dart             |  6 ++-
 .../screens/receipt/receipt_screen.dart            |  9 +++-
 .../screens/receipt/widgets/receipt_card.dart      | 13 ++++--
 .../lib/domain/repositories/adyen_repository.dart  | 34 ++++++++++++--
 .../presentation/app/bloc/payment_cards_cubit.dart |  1 -
 .../lib/presentation/app/bloc/payment_cubit.dart   | 51 +++++++++++++++------
 .../screens/payment_processing_page.dart           |  8 +++-
 27 files changed, 296 insertions(+), 161 deletions(-)

Diff

diff --git a/common/pubspec.lock b/common/pubspec.lock
index b4f4869e..6edf7a60 100644
--- a/common/pubspec.lock
+++ b/common/pubspec.lock
@@ -336,6 +336,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.11.0"
+ json_pretty:
+ dependency: "direct main"
+ description:
+ name: json_pretty
+ sha256: "03795063131b8e4af00fb95a5b09cfa98abb710298f9a891a321fb7349d1f600"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
leak_tracker:
dependency: transitive
description:
diff --git a/common/pubspec.yaml b/common/pubspec.yaml
index a46d5b49..2b8084a1 100644
--- a/common/pubspec.yaml
+++ b/common/pubspec.yaml
@@ -13,6 +13,7 @@ dependencies:
sdk: flutter
intl: any
csv: ^6.0.0
+ json_pretty: ^1.0.4
dev_dependencies:
flutter_test:
diff --git a/common/scripts/dart/sync_translations.dart b/common/scripts/dart/sync_translations.dart
index a8188b5f..d2dd7a9c 100644
--- a/common/scripts/dart/sync_translations.dart
+++ b/common/scripts/dart/sync_translations.dart
@@ -9,7 +9,7 @@ String _translationsUrl(String apiKey) {
}
Future<String> _loadApiKeyFromSecrets() async {
- final dotEnvFile = File("env/.prod.env");
+ final dotEnvFile = File("env/.env");
final lines = await dotEnvFile.readAsLines();
final apiKey = lines.firstWhere(
(line) => line.startsWith("GOOGLE_SHEETS_API_KEY"),
diff --git a/concierge/lib/_generated/data/remote/models/order.g.dart b/concierge/lib/_generated/data/remote/models/order.g.dart
index 740a2b05..0bcdea87 100644
--- a/concierge/lib/_generated/data/remote/models/order.g.dart
+++ b/concierge/lib/_generated/data/remote/models/order.g.dart
@@ -108,7 +108,7 @@ Map<String, dynamic> _$ImageToJson(Image instance) => <String, dynamic>{
OrderItem _$OrderItemFromJson(Map json) => OrderItem(
id: (json['id'] as num).toInt(),
- price: (json['price'] as num).toInt(),
+ price: (json['price'] as num).toDouble(),
quantity: (json['quantity'] as num).toInt(),
itemType: json['item_type'] as String,
alternativeName: json['alternative_name'] as String,
diff --git a/concierge/lib/_generated/presentation/screens/payment/bloc/payment_state.freezed.dart b/concierge/lib/_generated/presentation/screens/payment/bloc/payment_state.freezed.dart
index 10a782df..b23e0a1d 100644
--- a/concierge/lib/_generated/presentation/screens/payment/bloc/payment_state.freezed.dart
+++ b/concierge/lib/_generated/presentation/screens/payment/bloc/payment_state.freezed.dart
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$PaymentState {
- bool get isLoading; AppError get error;
+ bool get isLoading; int get orderId; bool get paymentSuccess; AppError get error;
/// Create a copy of PaymentState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -25,16 +25,16 @@ $PaymentStateCopyWith<PaymentState> get copyWith => _$PaymentStateCopyWithImpl<P
@override
bool operator ==(Object other) {
- return identical(this, other) || (other.runtimeType == runtimeType&&other is PaymentState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error));
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is PaymentState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.orderId, orderId) || other.orderId == orderId)&&(identical(other.paymentSuccess, paymentSuccess) || other.paymentSuccess == paymentSuccess)&&(identical(other.error, error) || other.error == error));
}
@override
-int get hashCode => Object.hash(runtimeType,isLoading,error);
+int get hashCode => Object.hash(runtimeType,isLoading,orderId,paymentSuccess,error);
@override
String toString() {
- return 'PaymentState(isLoading: $isLoading, error: $error)';
+ return 'PaymentState(isLoading: $isLoading, orderId: $orderId, paymentSuccess: $paymentSuccess, error: $error)';
}
@@ -45,7 +45,7 @@ abstract mixin class $PaymentStateCopyWith<$Res> {
factory $PaymentStateCopyWith(PaymentState value, $Res Function(PaymentState) _then) = _$PaymentStateCopyWithImpl;
@useResult
$Res call({
- bool isLoading, AppError error
+ bool isLoading, int orderId, bool paymentSuccess, AppError error
});
@@ -62,9 +62,11 @@ class _$PaymentStateCopyWithImpl<$Res>
/// Create a copy of PaymentState
/// with the given fields replaced by the non-null parameter values.
-@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? error = null,}) {
+@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? orderId = null,Object? paymentSuccess = null,Object? error = null,}) {
return _then(_self.copyWith(
isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
+as bool,orderId: null == orderId ? _self.orderId : orderId // ignore: cast_nullable_to_non_nullable
+as int,paymentSuccess: null == paymentSuccess ? _self.paymentSuccess : paymentSuccess // ignore: cast_nullable_to_non_nullable
as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
as AppError,
));
@@ -151,10 +153,10 @@ return $default(_that);case _:
/// }
/// ```
-@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, AppError error)? $default,{required TResult orElse(),}) {final _that = this;
+@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, int orderId, bool paymentSuccess, AppError error)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _PaymentState() when $default != null:
-return $default(_that.isLoading,_that.error);case _:
+return $default(_that.isLoading,_that.orderId,_that.paymentSuccess,_that.error);case _:
return orElse();
}
@@ -172,10 +174,10 @@ return $default(_that.isLoading,_that.error);case _:
/// }
/// ```
-@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, AppError error) $default,) {final _that = this;
+@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, int orderId, bool paymentSuccess, AppError error) $default,) {final _that = this;
switch (_that) {
case _PaymentState():
-return $default(_that.isLoading,_that.error);case _:
+return $default(_that.isLoading,_that.orderId,_that.paymentSuccess,_that.error);case _:
throw StateError('Unexpected subclass');
}
@@ -192,10 +194,10 @@ return $default(_that.isLoading,_that.error);case _:
/// }
/// ```
-@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, AppError error)? $default,) {final _that = this;
+@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, int orderId, bool paymentSuccess, AppError error)? $default,) {final _that = this;
switch (_that) {
case _PaymentState() when $default != null:
-return $default(_that.isLoading,_that.error);case _:
+return $default(_that.isLoading,_that.orderId,_that.paymentSuccess,_that.error);case _:
return null;
}
@@ -207,10 +209,12 @@ return $default(_that.isLoading,_that.error);case _:
class _PaymentState implements PaymentState {
- const _PaymentState({this.isLoading = false, this.error = AppError.none});
+ const _PaymentState({this.isLoading = false, this.orderId = 0, this.paymentSuccess = false, this.error = AppError.none});
@override@JsonKey() final bool isLoading;
+@override@JsonKey() final int orderId;
+@override@JsonKey() final bool paymentSuccess;
@override@JsonKey() final AppError error;
/// Create a copy of PaymentState
@@ -223,16 +227,16 @@ _$PaymentStateCopyWith<_PaymentState> get copyWith => __$PaymentStateCopyWithImp
@override
bool operator ==(Object other) {
- return identical(this, other) || (other.runtimeType == runtimeType&&other is _PaymentState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error));
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _PaymentState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.orderId, orderId) || other.orderId == orderId)&&(identical(other.paymentSuccess, paymentSuccess) || other.paymentSuccess == paymentSuccess)&&(identical(other.error, error) || other.error == error));
}
@override
-int get hashCode => Object.hash(runtimeType,isLoading,error);
+int get hashCode => Object.hash(runtimeType,isLoading,orderId,paymentSuccess,error);
@override
String toString() {
- return 'PaymentState(isLoading: $isLoading, error: $error)';
+ return 'PaymentState(isLoading: $isLoading, orderId: $orderId, paymentSuccess: $paymentSuccess, error: $error)';
}
@@ -243,7 +247,7 @@ abstract mixin class _$PaymentStateCopyWith<$Res> implements $PaymentStateCopyWi
factory _$PaymentStateCopyWith(_PaymentState value, $Res Function(_PaymentState) _then) = __$PaymentStateCopyWithImpl;
@override @useResult
$Res call({
- bool isLoading, AppError error
+ bool isLoading, int orderId, bool paymentSuccess, AppError error
});
@@ -260,9 +264,11 @@ class __$PaymentStateCopyWithImpl<$Res>
/// Create a copy of PaymentState
/// with the given fields replaced by the non-null parameter values.
-@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? error = null,}) {
+@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? orderId = null,Object? paymentSuccess = null,Object? error = null,}) {
return _then(_PaymentState(
isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
+as bool,orderId: null == orderId ? _self.orderId : orderId // ignore: cast_nullable_to_non_nullable
+as int,paymentSuccess: null == paymentSuccess ? _self.paymentSuccess : paymentSuccess // ignore: cast_nullable_to_non_nullable
as bool,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
as AppError,
));
diff --git a/concierge/lib/_generated/presentation/screens/receipt/bloc/receipt_state.freezed.dart b/concierge/lib/_generated/presentation/screens/receipt/bloc/receipt_state.freezed.dart
index a5458491..798010b8 100644
--- a/concierge/lib/_generated/presentation/screens/receipt/bloc/receipt_state.freezed.dart
+++ b/concierge/lib/_generated/presentation/screens/receipt/bloc/receipt_state.freezed.dart
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$ReceiptState {
- bool get isLoading; AppError get error;
+ bool get isLoading; List<OrderItem> get items; AppError get error;
/// Create a copy of ReceiptState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -25,16 +25,16 @@ $ReceiptStateCopyWith<ReceiptState> get copyWith => _$ReceiptStateCopyWithImpl<R
@override
bool operator ==(Object other) {
- return identical(this, other) || (other.runtimeType == runtimeType&&other is ReceiptState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error));
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is ReceiptState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&const DeepCollectionEquality().equals(other.items, items)&&(identical(other.error, error) || other.error == error));
}
@override
-int get hashCode => Object.hash(runtimeType,isLoading,error);
+int get hashCode => Object.hash(runtimeType,isLoading,const DeepCollectionEquality().hash(items),error);
@override
String toString() {
- return 'ReceiptState(isLoading: $isLoading, error: $error)';
+ return 'ReceiptState(isLoading: $isLoading, items: $items, error: $error)';
}
@@ -45,7 +45,7 @@ abstract mixin class $ReceiptStateCopyWith<$Res> {
factory $ReceiptStateCopyWith(ReceiptState value, $Res Function(ReceiptState) _then) = _$ReceiptStateCopyWithImpl;
@useResult
$Res call({
- bool isLoading, AppError error
+ bool isLoading, List<OrderItem> items, AppError error
});
@@ -62,10 +62,11 @@ class _$ReceiptStateCopyWithImpl<$Res>
/// Create a copy of ReceiptState
/// with the given fields replaced by the non-null parameter values.
-@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? error = null,}) {
+@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? items = null,Object? error = 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 bool,items: null == items ? _self.items : items // ignore: cast_nullable_to_non_nullable
+as List<OrderItem>,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
as AppError,
));
}
@@ -151,10 +152,10 @@ return $default(_that);case _:
/// }
/// ```
-@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, AppError error)? $default,{required TResult orElse(),}) {final _that = this;
+@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, List<OrderItem> items, AppError error)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _ReceiptState() when $default != null:
-return $default(_that.isLoading,_that.error);case _:
+return $default(_that.isLoading,_that.items,_that.error);case _:
return orElse();
}
@@ -172,10 +173,10 @@ return $default(_that.isLoading,_that.error);case _:
/// }
/// ```
-@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, AppError error) $default,) {final _that = this;
+@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, List<OrderItem> items, AppError error) $default,) {final _that = this;
switch (_that) {
case _ReceiptState():
-return $default(_that.isLoading,_that.error);case _:
+return $default(_that.isLoading,_that.items,_that.error);case _:
throw StateError('Unexpected subclass');
}
@@ -192,10 +193,10 @@ return $default(_that.isLoading,_that.error);case _:
/// }
/// ```
-@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, AppError error)? $default,) {final _that = this;
+@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, List<OrderItem> items, AppError error)? $default,) {final _that = this;
switch (_that) {
case _ReceiptState() when $default != null:
-return $default(_that.isLoading,_that.error);case _:
+return $default(_that.isLoading,_that.items,_that.error);case _:
return null;
}
@@ -207,10 +208,17 @@ return $default(_that.isLoading,_that.error);case _:
class _ReceiptState implements ReceiptState {
- const _ReceiptState({this.isLoading = false, this.error = AppError.none});
+ const _ReceiptState({this.isLoading = false, final List<OrderItem> items = const [], this.error = AppError.none}): _items = items;
@override@JsonKey() final bool isLoading;
+ final List<OrderItem> _items;
+@override@JsonKey() List<OrderItem> get items {
+ if (_items is EqualUnmodifiableListView) return _items;
+ // ignore: implicit_dynamic_type
+ return EqualUnmodifiableListView(_items);
+}
+
@override@JsonKey() final AppError error;
/// Create a copy of ReceiptState
@@ -223,16 +231,16 @@ _$ReceiptStateCopyWith<_ReceiptState> get copyWith => __$ReceiptStateCopyWithImp
@override
bool operator ==(Object other) {
- return identical(this, other) || (other.runtimeType == runtimeType&&other is _ReceiptState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.error, error) || other.error == error));
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _ReceiptState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&const DeepCollectionEquality().equals(other._items, _items)&&(identical(other.error, error) || other.error == error));
}
@override
-int get hashCode => Object.hash(runtimeType,isLoading,error);
+int get hashCode => Object.hash(runtimeType,isLoading,const DeepCollectionEquality().hash(_items),error);
@override
String toString() {
- return 'ReceiptState(isLoading: $isLoading, error: $error)';
+ return 'ReceiptState(isLoading: $isLoading, items: $items, error: $error)';
}
@@ -243,7 +251,7 @@ abstract mixin class _$ReceiptStateCopyWith<$Res> implements $ReceiptStateCopyWi
factory _$ReceiptStateCopyWith(_ReceiptState value, $Res Function(_ReceiptState) _then) = __$ReceiptStateCopyWithImpl;
@override @useResult
$Res call({
- bool isLoading, AppError error
+ bool isLoading, List<OrderItem> items, AppError error
});
@@ -260,10 +268,11 @@ class __$ReceiptStateCopyWithImpl<$Res>
/// Create a copy of ReceiptState
/// with the given fields replaced by the non-null parameter values.
-@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? error = null,}) {
+@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? items = null,Object? error = null,}) {
return _then(_ReceiptState(
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 bool,items: null == items ? _self._items : items // ignore: cast_nullable_to_non_nullable
+as List<OrderItem>,error: null == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
as AppError,
));
}
diff --git a/concierge/lib/_generated/presentation/screens/receipt/receipt_route.g.dart b/concierge/lib/_generated/presentation/screens/receipt/receipt_route.g.dart
index 55d63b20..8ac25044 100644
--- a/concierge/lib/_generated/presentation/screens/receipt/receipt_route.g.dart
+++ b/concierge/lib/_generated/presentation/screens/receipt/receipt_route.g.dart
@@ -14,10 +14,16 @@ RouteBase get $receiptRoute => GoRouteData.$route(
);
mixin $ReceiptRoute on GoRouteData {
- static ReceiptRoute _fromState(GoRouterState state) => ReceiptRoute();
+ static ReceiptRoute _fromState(GoRouterState state) =>
+ ReceiptRoute(orderId: int.parse(state.uri.queryParameters['order-id']!));
+
+ ReceiptRoute get _self => this as ReceiptRoute;
@override
- String get location => GoRouteData.$location('/concierge/receipt');
+ String get location => GoRouteData.$location(
+ '/concierge/receipt',
+ queryParams: {'order-id': _self.orderId.toString()},
+ );
@override
void go(BuildContext context) => context.go(location);
diff --git a/concierge/lib/concierge_route.dart b/concierge/lib/concierge_route.dart
index 565345aa..d5a683fc 100644
--- a/concierge/lib/concierge_route.dart
+++ b/concierge/lib/concierge_route.dart
@@ -40,15 +40,17 @@ final conciergeShellRoute = StatefulShellRoute.indexedStack(
),
],
builder: (context, state, child) {
- Future<(ConciergeService, ConciergeSecureStorage)> getDependencies() async {
- final flavorName = state.uri.queryParameters["flavor"].toString();
- final authToken = state.uri.queryParameters["auth-token"].toString();
- final subscriptionKey = state.uri.queryParameters["sub-key"].toString();
+ Future<(ConciergeService, ConciergeSecureStorage, Dio)> getDependencies() async {
+ final flavorName = state.uri.queryParameters["flavor"] ?? "";
+ final authToken = state.uri.queryParameters["auth-token"] ?? "";
+ final subscriptionKey = state.uri.queryParameters["sub-key"] ?? "";
final storage = ConciergeSecureStorage(FlutterSecureStorage());
if (state.uri.queryParameters.isNotEmpty) {
- await storage.setUserToken(authToken);
- await storage.setSubscriptionKey(subscriptionKey);
- F.appFlavor = Flavor.values.firstWhere((flavor) => flavor.name == flavorName);
+ if (authToken.isNotEmpty) await storage.setUserToken(authToken);
+ if (subscriptionKey.isNotEmpty) await storage.setSubscriptionKey(subscriptionKey);
+ if (flavorName.isNotEmpty) {
+ F.appFlavor = Flavor.values.firstWhere((flavor) => flavor.name == flavorName);
+ }
}
final dio = Dio(BaseOptions(baseUrl: F.baseUrl));
dio.interceptors.addAll([
@@ -65,7 +67,7 @@ final conciergeShellRoute = StatefulShellRoute.indexedStack(
if (kDebugMode) PrettyDioLogger(requestBody: true, requestHeader: true),
]);
await PaymentPlugin.initialize(config: PaymentConfig(dio: apimDio));
- return (ConciergeService(dio), storage);
+ return (ConciergeService(dio), storage, apimDio);
}
return FutureBuilder(
@@ -79,10 +81,11 @@ final conciergeShellRoute = StatefulShellRoute.indexedStack(
return Center(child: Text(asyncSnapshot.error.toString()));
}
- final (service, storage) = asyncSnapshot.data!;
+ final (service, storage, apimDio) = asyncSnapshot.data!;
return MultiRepositoryProvider(
providers: [
RepositoryProvider(create: (context) => PropertyRepository(service)),
+ RepositoryProvider(create: (context) => AdyenRepository(dio: apimDio)),
RepositoryProvider(create: (context) => storage),
RepositoryProvider(create: (context) => PaymentPlugin.instance),
],
diff --git a/concierge/lib/data/remote/api/concierge_service.dart b/concierge/lib/data/remote/api/concierge_service.dart
index ec645653..a972041b 100644
--- a/concierge/lib/data/remote/api/concierge_service.dart
+++ b/concierge/lib/data/remote/api/concierge_service.dart
@@ -12,7 +12,7 @@ part '../../../_generated/data/remote/api/concierge_service.g.dart';
@RestApi()
abstract class ConciergeService {
- factory ConciergeService(Dio dio, {String? baseUrl}) = _ConciergeService;
+ factory ConciergeService(Dio dio) = _ConciergeService;
@GET("/hotels/domains/{hotelCode}")
Future<ApiResponse<Property>> getHotelOverview(@Path("hotelCode") String hotelCode);
diff --git a/concierge/lib/data/remote/models/order.dart b/concierge/lib/data/remote/models/order.dart
index 248ead5a..2f8355de 100644
--- a/concierge/lib/data/remote/models/order.dart
+++ b/concierge/lib/data/remote/models/order.dart
@@ -120,7 +120,7 @@ class Image {
@JsonSerializable(fieldRename: FieldRename.snake)
class OrderItem {
final int id;
- final int price;
+ final double price;
final int quantity;
final String itemType;
final String alternativeName;
diff --git a/concierge/lib/domain/repositories/property_repository.dart b/concierge/lib/domain/repositories/property_repository.dart
index a3f3e780..93b69baf 100644
--- a/concierge/lib/domain/repositories/property_repository.dart
+++ b/concierge/lib/domain/repositories/property_repository.dart
@@ -72,8 +72,8 @@ class PropertyRepository {
return response.data;
}
- Future<Order> getOrder(String id) async {
- final response = await _service.getOrder(id);
+ Future<Order> getOrder(int id) async {
+ final response = await _service.getOrder(id.toString());
return response.data;
}
diff --git a/concierge/lib/flavors.dart b/concierge/lib/flavors.dart
index 14e472cf..a03a70d4 100644
--- a/concierge/lib/flavors.dart
+++ b/concierge/lib/flavors.dart
@@ -9,7 +9,7 @@ class F {
static Flavor get appFlavor => _appFlavor!;
static set appFlavor(Flavor flavor) {
- _appFlavor = flavor;
+ _appFlavor ??= flavor;
}
static String get name => appFlavor.name;
diff --git a/concierge/lib/presentation/screens/confirm_order/confirm_order_screen.dart b/concierge/lib/presentation/screens/confirm_order/confirm_order_screen.dart
index b7ddc537..e6704f35 100644
--- a/concierge/lib/presentation/screens/confirm_order/confirm_order_screen.dart
+++ b/concierge/lib/presentation/screens/confirm_order/confirm_order_screen.dart
@@ -66,8 +66,15 @@ class ConfirmOrderScreen extends StatelessWidget {
final cartCubit = context.read<CartCubit>();
yield Divider(color: Colors.grey.shade300);
for (final product in cartCubit.products) {
+ final cartCubit = context.read<CartCubit>();
+ final quantity = cartCubit.getQuantity(product.id);
+ final price = product.price * quantity;
yield const Gap(12);
- yield ConfirmOrderProductListTile(product: product);
+ yield ConfirmOrderProductListTile(
+ title: product.title,
+ price: price,
+ quantity: quantity,
+ );
yield const Gap(12);
yield Divider(color: Colors.grey.shade300);
}
diff --git a/concierge/lib/presentation/screens/confirm_order/widgets/confirm_order_product_list_tile.dart b/concierge/lib/presentation/screens/confirm_order/widgets/confirm_order_product_list_tile.dart
index 6d3f7aa4..dae41f49 100644
--- a/concierge/lib/presentation/screens/confirm_order/widgets/confirm_order_product_list_tile.dart
+++ b/concierge/lib/presentation/screens/confirm_order/widgets/confirm_order_product_list_tile.dart
@@ -1,26 +1,27 @@
-import 'package:concierge/data/remote/models/product.dart';
-import 'package:concierge/presentation/app/cart_cubit.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
class ConfirmOrderProductListTile extends StatelessWidget {
- const ConfirmOrderProductListTile({super.key, required this.product});
+ const ConfirmOrderProductListTile({
+ super.key,
+ required this.title,
+ required this.quantity,
+ required this.price,
+ });
- final Product product;
+ final String title;
+ final int quantity;
+ final double price;
@override
Widget build(BuildContext context) {
- final cartCubit = context.read<CartCubit>();
- final quantity = cartCubit.getQuantity(product.id);
- final price = product.price * quantity;
return Row(
children: [
Text("${quantity}x"),
const Gap(16),
Expanded(
child: Text(
- product.title,
+ title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
diff --git a/concierge/lib/presentation/screens/payment/bloc/payment_cubit.dart b/concierge/lib/presentation/screens/payment/bloc/payment_cubit.dart
index 0214097e..27285b78 100644
--- a/concierge/lib/presentation/screens/payment/bloc/payment_cubit.dart
+++ b/concierge/lib/presentation/screens/payment/bloc/payment_cubit.dart
@@ -5,18 +5,26 @@ import 'package:concierge/presentation/base/base_cubit.dart';
import 'package:concierge/presentation/screens/payment/bloc/payment_state.dart';
import 'package:payment_plugin/payment_plugin.dart';
import 'package:payment_plugin/utils/json.dart';
+import 'package:payment_plugin/presentation/app/bloc/payment_cubit.dart' as payment_plugin;
class PaymentCubit extends BaseCubit<PaymentState> {
final CartCubit _cartCubit;
final PropertyRepository _propertyRepository;
final PaymentPlugin _paymentPlugin;
+ final payment_plugin.PaymentCubit _paymentCubit;
PaymentCubit(
this._cartCubit,
this._propertyRepository,
this._paymentPlugin,
+ this._paymentCubit,
) : super(const PaymentState()) {
init();
+ _paymentCubit.stream.listen((state) {
+ if (state is PaymentProcessingStateConfirmed) {
+ _checkStatus();
+ }
+ });
}
Future<void> init() async {
@@ -42,7 +50,7 @@ class PaymentCubit extends BaseCubit<PaymentState> {
},
);
final area = _cartCubit.state.selectedArea!;
- final response = await _propertyRepository.createOrder(
+ final orderResponse = await _propertyRepository.createOrder(
products: products.toList(),
areaId: area.id,
isDelivery: _cartCubit.state.isDelivery,
@@ -52,13 +60,16 @@ class PaymentCubit extends BaseCubit<PaymentState> {
comment: _cartCubit.state.comment,
chargeToRoom: _cartCubit.state.chargeToRoom,
);
-
+ safeEmit(state.copyWith(orderId: orderResponse.id));
final sessionResponse = await _paymentPlugin.repository.createAdyenSessionForConcierge(
- response.id,
+ orderResponse.id,
);
final data = Json.of(sessionResponse);
final clientKey = data["clientKey"];
- final sessionData = Json.of(data["sessionResponse"]);
+ final session = Json.of(data["sessionResponse"]);
+ final sessionData = session["sessionData"];
+ final sessionId = session["id"];
+ await _paymentCubit.createConciergeSession(sessionId, clientKey, sessionData);
print(data);
} catch (e, st) {
handleError(e, st);
@@ -67,4 +78,18 @@ class PaymentCubit extends BaseCubit<PaymentState> {
safeEmit(state.copyWith(isLoading: false));
}
}
+
+ Future<void> _checkStatus() async {
+ try {
+ final response = await _propertyRepository.getOrder(state.orderId);
+ if (response.status == "RECEIVED") {
+ safeEmit(state.copyWith(paymentSuccess: true));
+ } else {
+ await Future.delayed(Duration(seconds: 1));
+ _checkStatus();
+ }
+ } catch (e, st) {
+ handleError(e, st);
+ }
+ }
}
diff --git a/concierge/lib/presentation/screens/payment/bloc/payment_state.dart b/concierge/lib/presentation/screens/payment/bloc/payment_state.dart
index 6875d33b..0e0d3472 100644
--- a/concierge/lib/presentation/screens/payment/bloc/payment_state.dart
+++ b/concierge/lib/presentation/screens/payment/bloc/payment_state.dart
@@ -7,6 +7,8 @@ part '../../../../_generated/presentation/screens/payment/bloc/payment_state.fre
abstract class PaymentState with _$PaymentState {
const factory PaymentState({
@Default(false) bool isLoading,
+ @Default(0) int orderId,
+ @Default(false) bool paymentSuccess,
@Default(AppError.none) AppError error,
}) = _PaymentState;
}
\ No newline at end of file
diff --git a/concierge/lib/presentation/screens/payment/payment_route.dart b/concierge/lib/presentation/screens/payment/payment_route.dart
index a34e72e6..e03e2368 100644
--- a/concierge/lib/presentation/screens/payment/payment_route.dart
+++ b/concierge/lib/presentation/screens/payment/payment_route.dart
@@ -4,6 +4,7 @@ import 'package:concierge/presentation/navigation/app_routes.dart';
import 'package:go_router/go_router.dart';
import 'package:concierge/presentation/screens/payment/bloc/payment_cubit.dart';
import 'package:concierge/presentation/screens/payment/payment_screen.dart';
+import 'package:payment_plugin/presentation/app/bloc/payment_cubit.dart' as payment_plugin;
import '../../navigation/transitions/slide_in_transition.dart';
@@ -15,12 +16,20 @@ class PaymentRoute extends GoRouteData with $PaymentRoute {
Page<void> buildPage(BuildContext context, GoRouterState state) {
return slideInTransition(
state: state,
- child: BlocProvider(
- create: (context) => PaymentCubit(
- context.read(),
- context.read(),
- context.read(),
- ),
+ child: MultiBlocProvider(
+ providers: [
+ BlocProvider(
+ create: (context) => payment_plugin.PaymentCubit(adyenRepository: context.read()),
+ ),
+ BlocProvider(
+ create: (context) => PaymentCubit(
+ context.read(),
+ context.read(),
+ context.read(),
+ context.read(),
+ ),
+ ),
+ ],
child: PaymentScreen(),
),
);
diff --git a/concierge/lib/presentation/screens/payment/payment_screen.dart b/concierge/lib/presentation/screens/payment/payment_screen.dart
index 73c0676c..6f314edf 100644
--- a/concierge/lib/presentation/screens/payment/payment_screen.dart
+++ b/concierge/lib/presentation/screens/payment/payment_screen.dart
@@ -3,6 +3,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:concierge/presentation/screens/payment/bloc/payment_cubit.dart';
import 'package:concierge/presentation/screens/payment/bloc/payment_state.dart';
+import 'package:payment_plugin/presentation/screens/payment_processing_page.dart'
+ show PaymentProcessingPage;
+import 'package:payment_plugin/presentation/app/bloc/payment_cubit.dart' as payment_plugin;
+import 'package:payment_plugin/presentation/app/bloc/payment_processing_state.dart'
+ as payment_plugin;
class PaymentScreen extends StatelessWidget {
const PaymentScreen({super.key});
@@ -12,34 +17,28 @@ class PaymentScreen extends StatelessWidget {
return BlocBuilder<PaymentCubit, PaymentState>(
builder: (context, state) {
final cubit = context.read<PaymentCubit>();
- return MultiBlocListener(
- listeners: [
- BlocListener<PaymentCubit, PaymentState>(
- listenWhen: (prev, curr) =>
- prev.isLoading && curr.error.isError,
- listener: (context, state) {
- },
- )
- ],
- child: Scaffold(
- appBar: AppBar(),
- body: Center(
- child: Column(
- children: [
- Text("Payment"),
- Text("SUCCESS!"),
- TextButton(
- onPressed: () {
- ReceiptRoute().push(context);
- },
- child: Text("Gå til kvittering"),
- )
- ],
+ return BlocBuilder<payment_plugin.PaymentCubit, payment_plugin.PaymentProcessingState>(
+ builder: (context, state) {
+ return MultiBlocListener(
+ listeners: [
+ BlocListener<PaymentCubit, PaymentState>(
+ listenWhen: (prev, curr) => prev.isLoading && curr.error.isError,
+ listener: (context, state) {},
+ ),
+ BlocListener<PaymentCubit, PaymentState>(
+ listenWhen: (prev, curr) => !prev.paymentSuccess && curr.paymentSuccess,
+ listener: (context, state) {
+ ReceiptRoute(orderId: state.orderId).pushReplacement(context);
+ },
+ ),
+ ],
+ child: Material(
+ child: PaymentProcessingPage(),
),
- ),
- ),
+ );
+ },
);
},
);
- }
-}
\ No newline at end of file
+ }
+}
diff --git a/concierge/lib/presentation/screens/receipt/bloc/receipt_cubit.dart b/concierge/lib/presentation/screens/receipt/bloc/receipt_cubit.dart
index 8022e886..85931d7c 100644
--- a/concierge/lib/presentation/screens/receipt/bloc/receipt_cubit.dart
+++ b/concierge/lib/presentation/screens/receipt/bloc/receipt_cubit.dart
@@ -1,38 +1,27 @@
-import 'package:concierge/data/remote/models/product.dart';
+import 'package:concierge/domain/models/app_error.dart';
+import 'package:concierge/domain/repositories/property_repository.dart';
import 'package:concierge/presentation/base/base_cubit.dart';
import 'package:concierge/presentation/screens/receipt/bloc/receipt_state.dart';
class ReceiptCubit extends BaseCubit<ReceiptState> {
- ReceiptCubit() : super(const ReceiptState()) {
+ final int orderId;
+ final PropertyRepository _propertyRepository;
+
+ ReceiptCubit(this._propertyRepository, {required this.orderId}) : super(const ReceiptState()) {
init();
}
- Product get mockProduct => Product.fromJson({
- "id": 1603,
- "title": "Pepsi",
- "sub_title": "25 cl",
- "body": "<div>Pepsi er en velsmagende sodavand med sukker.</div>",
- "allergies": "",
- "price": 43,
- "price_comwell_club": null,
- "estimated_delivery_time": "15 min.",
- "is_new": 0,
- "images": [
- {
- "url":
- "https://admin-stage.concierge.comwell.com/storage/media/2515/Comwell_Consierge_RAIS1706.jpg",
- "preload":
- "https://admin-stage.concierge.comwell.com/storage/media/2515/conversi ons/Comwell_Consierge_RAIS1706-preload.jpg",
- "thumbnail":
- "https://admin-stage.concierge.comwell.com/storage/media/2515/conversions/Comwell_Consierge_RAIS1706-thumbnail.jpg",
- "product_hero":
- "https://admin-stage.concierge.comwell.com/storage/media/2515/conversions/Comwell_Consierge_RAIS1706-product_hero.jpg",
- "alt": "Comwell_Consierge_RAIS1706.jpg",
- },
- ],
- "options": [],
- "type": "PRODUCT",
- });
-
- Future<void> init() async {}
+ Future<void> init() async {
+ try {
+ safeEmit(state.copyWith(isLoading: true));
+ final response = await _propertyRepository.getOrder(orderId);
+ final products = response.orderItems;
+ safeEmit(state.copyWith(items: products));
+ } catch (e, st) {
+ handleError(e, st);
+ safeEmit(state.copyWith(error: AppError.unknown(e.toString())));
+ } finally {
+ safeEmit(state.copyWith(isLoading: false));
+ }
+ }
}
diff --git a/concierge/lib/presentation/screens/receipt/bloc/receipt_state.dart b/concierge/lib/presentation/screens/receipt/bloc/receipt_state.dart
index 9b6340a4..7b8d8524 100644
--- a/concierge/lib/presentation/screens/receipt/bloc/receipt_state.dart
+++ b/concierge/lib/presentation/screens/receipt/bloc/receipt_state.dart
@@ -1,3 +1,4 @@
+import 'package:concierge/data/remote/models/order.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:concierge/domain/models/app_error.dart';
@@ -7,6 +8,7 @@ part '../../../../_generated/presentation/screens/receipt/bloc/receipt_state.fre
abstract class ReceiptState with _$ReceiptState {
const factory ReceiptState({
@Default(false) bool isLoading,
+ @Default([]) List<OrderItem> items,
@Default(AppError.none) AppError error,
}) = _ReceiptState;
-}
\ No newline at end of file
+}
diff --git a/concierge/lib/presentation/screens/receipt/receipt_route.dart b/concierge/lib/presentation/screens/receipt/receipt_route.dart
index 3fac7b14..66be534b 100644
--- a/concierge/lib/presentation/screens/receipt/receipt_route.dart
+++ b/concierge/lib/presentation/screens/receipt/receipt_route.dart
@@ -11,12 +11,16 @@ part '../../../_generated/presentation/screens/receipt/receipt_route.g.dart';
@TypedGoRoute<ReceiptRoute>(path: AppRoutes.receipt)
class ReceiptRoute extends GoRouteData with $ReceiptRoute {
+ final int orderId;
+
+ const ReceiptRoute({required this.orderId});
+
@override
Page<void> buildPage(BuildContext context, GoRouterState state) {
return slideInTransition(
state: state,
child: BlocProvider(
- create: (context) => ReceiptCubit(),
+ create: (context) => ReceiptCubit(context.read(), orderId: orderId),
child: ReceiptScreen(),
),
);
diff --git a/concierge/lib/presentation/screens/receipt/receipt_screen.dart b/concierge/lib/presentation/screens/receipt/receipt_screen.dart
index c2601dc7..dca983f3 100644
--- a/concierge/lib/presentation/screens/receipt/receipt_screen.dart
+++ b/concierge/lib/presentation/screens/receipt/receipt_screen.dart
@@ -43,7 +43,14 @@ class ReceiptScreen extends StatelessWidget {
Gap(32),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 50.0),
- child: ReceiptCard(),
+ child: Builder(
+ builder: (context) {
+ if (state.isLoading) {
+ return Center(child: CircularProgressIndicator());
+ }
+ return ReceiptCard();
+ },
+ ),
),
Gap(32),
Padding(
diff --git a/concierge/lib/presentation/screens/receipt/widgets/receipt_card.dart b/concierge/lib/presentation/screens/receipt/widgets/receipt_card.dart
index 7f566fa8..69412029 100644
--- a/concierge/lib/presentation/screens/receipt/widgets/receipt_card.dart
+++ b/concierge/lib/presentation/screens/receipt/widgets/receipt_card.dart
@@ -1,6 +1,7 @@
import 'package:common/localization/l10n_utils.dart';
import 'package:concierge/presentation/app/cart_cubit.dart';
import 'package:concierge/presentation/screens/confirm_order/widgets/confirm_order_product_list_tile.dart';
+import 'package:concierge/presentation/screens/receipt/bloc/receipt_cubit.dart';
import 'package:concierge/presentation/widgets/padded_column.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -32,7 +33,7 @@ class ReceiptCard extends StatelessWidget {
Padding(
padding: EdgeInsets.all(12),
child: Text(
- "${context.strings.order_to_room} 108",
+ "${context.strings.order_to_room} 106",
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
@@ -81,10 +82,14 @@ class ReceiptCard extends StatelessWidget {
}
Iterable<Widget> buildOrder(BuildContext context) sync* {
- final cubit = context.read<CartCubit>();
+ final cubit = context.read<ReceiptCubit>();
yield Divider(color: Colors.grey.shade300);
- for (final product in cubit.products) {
- yield ConfirmOrderProductListTile(product: product);
+ for (final orderItem in cubit.state.items) {
+ yield ConfirmOrderProductListTile(
+ quantity: orderItem.quantity,
+ price: orderItem.price.toDouble(),
+ title: orderItem.alternativeName,
+ );
yield Divider(color: Colors.grey.shade300);
}
}
diff --git a/payment_plugin/lib/domain/repositories/adyen_repository.dart b/payment_plugin/lib/domain/repositories/adyen_repository.dart
index 3930adaa..1a2c2f54 100644
--- a/payment_plugin/lib/domain/repositories/adyen_repository.dart
+++ b/payment_plugin/lib/domain/repositories/adyen_repository.dart
@@ -46,10 +46,7 @@ class AdyenRepository {
}
Future<dynamic> createAdyenSessionForConcierge(int orderId) async {
- final data = {
- "OrderId": orderId,
- "ReturnUrl": "comwell://"
- };
+ final data = {"OrderId": orderId, "ReturnUrl": "comwell://"};
return _api.createAdyenSessionForConcierge(data);
}
@@ -140,6 +137,35 @@ class AdyenRepository {
);
}
+ Future<PaymentConfigurations> createSession(
+ String sessionId,
+ String clientKey,
+ String sessionData,
+ ) async {
+ final amount = Amount(value: 123, currency: "DKK");
+ final session = await AdyenCheckout.session.create(
+ sessionData: sessionData,
+ sessionId: sessionId,
+ configuration: dropInConfiguration(amount, clientKey, false),
+ );
+
+ final availablePaymentMethods =
+ await _api.listAvailablePaymentMethods() as Map<String, dynamic>;
+
+ final scheme = _findPaymentMethod(availablePaymentMethods, "scheme");
+ final googlePay = _findPaymentMethod(availablePaymentMethods, "googlePay");
+ final applePay = _findPaymentMethod(availablePaymentMethods, "applePay");
+ return PaymentConfigurations(
+ sessionCheckout: session,
+ dropInConfiguration: dropInConfiguration(amount, clientKey, false),
+ googlePayConfiguration: _getGooglePayComponentConfig(clientKey),
+ cardComponentConfiguration: cardComponentConfiguration(amount, clientKey),
+ applePayConfiguration: _applePayComponentConfiguration(clientKey, amount, false),
+ isFullyPaidWithPoints: false,
+ availablePaymentMethods: [scheme!, googlePay!, applePay!],
+ );
+ }
+
Future<PaymentConfigurations?> fetchSessionForAddingCard() async {
final body = {"returnUrl": returnUrl};
final json = jsonEncode(body);
diff --git a/payment_plugin/lib/presentation/app/bloc/payment_cards_cubit.dart b/payment_plugin/lib/presentation/app/bloc/payment_cards_cubit.dart
index e64a379d..f55715b4 100644
--- a/payment_plugin/lib/presentation/app/bloc/payment_cards_cubit.dart
+++ b/payment_plugin/lib/presentation/app/bloc/payment_cards_cubit.dart
@@ -15,7 +15,6 @@ import 'package:payment_plugin/presentation/app/bloc/payment_cards_state.dart';
class PaymentCardsCubit extends Cubit<PaymentCardsState> {
final AdyenRepository adyenRepository;
-
late PaymentConfigurations? paymentConfigurations;
void Function(StoredPaymentMethod)? onPaymentMethodSelected;
diff --git a/payment_plugin/lib/presentation/app/bloc/payment_cubit.dart b/payment_plugin/lib/presentation/app/bloc/payment_cubit.dart
index d9ef70fa..9dcfe68a 100644
--- a/payment_plugin/lib/presentation/app/bloc/payment_cubit.dart
+++ b/payment_plugin/lib/presentation/app/bloc/payment_cubit.dart
@@ -7,21 +7,26 @@ import 'package:payment_plugin/presentation/app/bloc/payment_processing_state.da
class PaymentCubit extends Cubit<PaymentProcessingState> {
final AdyenRepository adyenRepository;
- PaymentCubit({required this.adyenRepository})
- : super(PaymentProcessingStateNotStarted());
+ PaymentCubit({required this.adyenRepository}) : super(PaymentProcessingStateNotStarted());
- Future<void> createSession(int price, String confirmationId,
- bool applyClubPoints, String hotelCode) async {
+ Future<void> createSession(
+ int price,
+ String confirmationId,
+ bool applyClubPoints,
+ String hotelCode,
+ ) async {
try {
emit(PaymentProcessingStateProcessing());
- final paymentConfigurations = await adyenRepository
- .sessionCheckout(hotelCode, confirmationId, applyClubPoints);
+ final paymentConfigurations = await adyenRepository.sessionCheckout(
+ hotelCode,
+ confirmationId,
+ applyClubPoints,
+ );
if (paymentConfigurations == null) {
emit(PaymentProcessingStateConfirmed());
} else {
- emit(PaymentProcessingStateSessionReceived(
- paymentConfigurations: paymentConfigurations));
+ emit(PaymentProcessingStateSessionReceived(paymentConfigurations: paymentConfigurations));
}
} catch (e) {
emit(PaymentProcessingStateError(message: "Error creating session"));
@@ -29,14 +34,34 @@ class PaymentCubit extends Cubit<PaymentProcessingState> {
}
}
+ Future<void> createConciergeSession(
+ String sessionId,
+ String clientKey,
+ String sessionData,
+ ) async {
+ try {
+ emit(PaymentProcessingStateProcessing());
+ final paymentConfigurations = await adyenRepository.createSession(
+ sessionId,
+ clientKey,
+ sessionData,
+ );
+ emit(PaymentProcessingStateSessionReceived(paymentConfigurations: paymentConfigurations));
+ } catch (e) {
+ print("qqq payment Error = $e");
+ emit(PaymentProcessingStateError(message: "Error creating session"));
+ await Future<void>.delayed(const Duration(milliseconds: 1000));
+ }
+ }
+
Future<void> onPaymentResult(PaymentResult result) async {
switch (result) {
- case PaymentAdvancedFinished():
- case PaymentSessionFinished():
+ case PaymentAdvancedFinished _:
+ case PaymentSessionFinished _:
emit(PaymentProcessingStateConfirmed());
break;
- case PaymentCancelledByUser():
- case PaymentError():
+ case PaymentCancelledByUser _:
+ case PaymentError _:
emit(PaymentProcessingStateError(message: "Error processing payment"));
}
}
@@ -44,6 +69,4 @@ class PaymentCubit extends Cubit<PaymentProcessingState> {
void onUserDismissPaymentPopup() {
emit(PaymentProcessingStateNotStarted());
}
-
-
}
diff --git a/payment_plugin/lib/presentation/screens/payment_processing_page.dart b/payment_plugin/lib/presentation/screens/payment_processing_page.dart
index 99656f4f..79287c5c 100644
--- a/payment_plugin/lib/presentation/screens/payment_processing_page.dart
+++ b/payment_plugin/lib/presentation/screens/payment_processing_page.dart
@@ -46,7 +46,7 @@ class _PaymentProcessingPageState extends State<PaymentProcessingPage>
void playError() async {
loadingComposition?.playBetween(animationController, "error", repeat: true);
- await Future<void>.delayed(const Duration(seconds: 1));
+ await Future<void>.delayed(const Duration(seconds: 2));
if (mounted) Navigator.of(context).pop();
}
@@ -84,15 +84,19 @@ class _PaymentProcessingPageState extends State<PaymentProcessingPage>
@override
Widget build(BuildContext context) {
- final cubit = context.read<PaymentCubit>();
+ final cubit = context.watch<PaymentCubit>();
return Scaffold(
body: Container(
alignment: Alignment.center,
color: sandColor[80],
child: BlocListener<PaymentCubit, PaymentProcessingState>(
+ listenWhen: (prev, curr) => prev != curr,
listener: (context, state) {
+ print("qqq paymentProcessingState=${state.runtimeType}");
if (state is PaymentProcessingStateSessionReceived) {
showAdyenModal(context);
+ } else if (state is PaymentProcessingStateError) {
+ playError();
}
},
child: Lottie.asset(