6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit 010c3d67
Changed files
.../lib/check_out/bloc/check_out_cubit.dart | 23 ++-- .../check_out/models/payment_configurations.dart | 4 +- .../check_out/pages/check_out_processing_page.dart | 1 - .../lib/payment/cubit/payment_cubit.dart | 60 ++++++++++ .../payment/cubit/payment_processing_state.dart | 23 ++++ .../lib/payment/payment_processing_page.dart | 129 +++++++++++++++++++++ .../pregistration/pregistration_repository.dart | 12 +- 7 files changed, 235 insertions(+), 17 deletions(-)
Diff
diff --git a/comwell_key_app/lib/check_out/bloc/check_out_cubit.dart b/comwell_key_app/lib/check_out/bloc/check_out_cubit.dart
index 60f0dd9b..2c313c39 100644
--- a/comwell_key_app/lib/check_out/bloc/check_out_cubit.dart
+++ b/comwell_key_app/lib/check_out/bloc/check_out_cubit.dart
@@ -104,9 +104,7 @@ class CheckoutCubit extends Cubit<CheckoutState> {
if (!state.isTermsAccepted && (booking.balance ?? 0.0) > 0.0) {
emit(state.showAcceptTermsError());
} else {
- //Check if the balance is 0 or if the club points are equal to the balance
- if (booking.balance == 0 ||
- (state.applyClubPoints && state.clubPoints == booking.balance)) {
+ if (booking.balance == 0) {
processCheckoutWithoutPaying();
} else {
processCheckout();
@@ -158,7 +156,7 @@ class CheckoutCubit extends Cubit<CheckoutState> {
await profileRepository.getBookingDetails(booking.confirmationId);
}
emit(state.processingStateUpdated(CheckoutProcessingStateProcessing()));
- if (booking.balance != 0) {
+ if (booking.balance == 0) {
await checkOutRepository.checkOut(booking.confirmationId);
} else {
emit(state.processingStateUpdated(
@@ -174,18 +172,23 @@ class CheckoutCubit extends Cubit<CheckoutState> {
Future<void> createSession() async {
try {
- final bookingPrice = totalPriceAfterDiscount;
final amount = Amount(
- value: bookingPrice,
+ value: booking.balance?.toInt() ?? 0,
currency: currency,
);
- print("qqq applyClubPoints ${state.applyClubPoints}");
+
final paymentConfigurations =
await preregistrationRepository.sessionCheckout(
amount, booking.confirmationId, state.applyClubPoints);
- emit(state.processingStateUpdated(CheckoutProcessingStateSessionReceived(
- paymentConfigurations: paymentConfigurations)));
- await Future<void>.delayed(const Duration(milliseconds: 4000));
+ if (paymentConfigurations.isFullyPaidWithPoints) {
+ checkOut();
+
+ } else {
+ await Future<void>.delayed(const Duration(milliseconds: 4000));
+ emit(state.processingStateUpdated(CheckoutProcessingStateSessionReceived(
+ paymentConfigurations: paymentConfigurations)));
+ }
+
} catch (e) {
emit(state.processingStateUpdated(
CheckoutProcessingStateError(message: "Error creating session")));
diff --git a/comwell_key_app/lib/check_out/models/payment_configurations.dart b/comwell_key_app/lib/check_out/models/payment_configurations.dart
index 27318571..ca188135 100644
--- a/comwell_key_app/lib/check_out/models/payment_configurations.dart
+++ b/comwell_key_app/lib/check_out/models/payment_configurations.dart
@@ -6,6 +6,7 @@ class PaymentConfigurations {
final DropInConfiguration dropInConfiguration;
final CardComponentConfiguration cardComponentConfiguration;
final ApplePayComponentConfiguration applePayConfiguration;
+ final bool isFullyPaidWithPoints;
PaymentConfigurations({
required this.cardComponentConfiguration,
@@ -13,10 +14,11 @@ class PaymentConfigurations {
required this.googlePayConfiguration,
required this.dropInConfiguration,
required this.applePayConfiguration,
+ required this.isFullyPaidWithPoints,
});
@override
String toString() {
- return 'PaymentConfigurations(sessionCheckout: $sessionCheckout, googlePayConfiguration: $googlePayConfiguration, dropInConfiguration: $dropInConfiguration, cardComponentConfiguration: $cardComponentConfiguration, applePayConfiguration: $applePayConfiguration)';
+ return 'PaymentConfigurations(sessionCheckout: $sessionCheckout, googlePayConfiguration: $googlePayConfiguration, dropInConfiguration: $dropInConfiguration, cardComponentConfiguration: $cardComponentConfiguration, applePayConfiguration: $applePayConfiguration, isFullyPaidWithPoints: $isFullyPaidWithPoints)';
}
}
diff --git a/comwell_key_app/lib/check_out/pages/check_out_processing_page.dart b/comwell_key_app/lib/check_out/pages/check_out_processing_page.dart
index ba7276de..d9764694 100644
--- a/comwell_key_app/lib/check_out/pages/check_out_processing_page.dart
+++ b/comwell_key_app/lib/check_out/pages/check_out_processing_page.dart
@@ -114,7 +114,6 @@ class _CheckOutProcessingPageState extends State<CheckOutProcessingPage>
controller: animationController,
onLoaded: (composition) {
if (loadingComposition == null) {
-
loadingComposition = composition;
animationController.duration = composition.duration;
switch (cubit.state.processingState) {
diff --git a/comwell_key_app/lib/payment/cubit/payment_cubit.dart b/comwell_key_app/lib/payment/cubit/payment_cubit.dart
new file mode 100644
index 00000000..6f1570a3
--- /dev/null
+++ b/comwell_key_app/lib/payment/cubit/payment_cubit.dart
@@ -0,0 +1,60 @@
+import 'package:adyen_checkout/adyen_checkout.dart';
+import 'package:comwell_key_app/pregistration/pregistration_repository.dart';
+import 'package:comwell_key_app/payment/cubit/payment_processing_state.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class PaymentCubit extends Cubit<PaymentProcessingState> {
+ late int totalPriceAfterDiscount;
+ late String currency;
+ late String confirmationId;
+ late bool applyClubPoints;
+ final PreregistrationRepository preregistrationRepository;
+
+ PaymentCubit({required this.preregistrationRepository})
+ : super(PaymentProcessingStateNotStarted());
+
+ Future<void> createSession() async {
+
+ emit(PaymentProcessingStateProcessing());
+
+ try {
+ final bookingPrice = totalPriceAfterDiscount;
+ final amount = Amount(
+ value: bookingPrice,
+ currency: currency,
+ );
+
+ final paymentConfigurations = await preregistrationRepository
+ .sessionCheckout(amount, confirmationId, applyClubPoints);
+ emit(PaymentProcessingStateSessionReceived(
+ paymentConfigurations: paymentConfigurations));
+ await Future<void>.delayed(const Duration(milliseconds: 4000));
+ emit(PaymentProcessingPaymentStateSuccess());
+ } catch (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():
+ emit(PaymentProcessingPaymentStateSuccess());
+ emit(PaymentProcessingStateConfirmed());
+ //This is here to add time so that the payment is represented in the BookingDetails
+
+ break;
+ case PaymentCancelledByUser():
+ case PaymentError():
+ emit(PaymentProcessingStateError(message: "Error processing payment"));
+ }
+ }
+
+
+
+
+ void onUserDismissPaymentPopup() {
+ emit(PaymentProcessingStateNotStarted());
+ }
+}
diff --git a/comwell_key_app/lib/payment/cubit/payment_processing_state.dart b/comwell_key_app/lib/payment/cubit/payment_processing_state.dart
new file mode 100644
index 00000000..9749b879
--- /dev/null
+++ b/comwell_key_app/lib/payment/cubit/payment_processing_state.dart
@@ -0,0 +1,23 @@
+import 'package:comwell_key_app/check_out/models/payment_configurations.dart';
+
+sealed class PaymentProcessingState {}
+
+class PaymentProcessingStateNotStarted extends PaymentProcessingState {}
+
+class PaymentProcessingStateProcessing extends PaymentProcessingState {}
+
+class PaymentProcessingStateSessionReceived extends PaymentProcessingState {
+ final PaymentConfigurations paymentConfigurations;
+
+ PaymentProcessingStateSessionReceived({required this.paymentConfigurations});
+}
+
+class PaymentProcessingPaymentStateSuccess extends PaymentProcessingState {}
+
+class PaymentProcessingStateConfirmed extends PaymentProcessingState {}
+
+class PaymentProcessingStateError extends PaymentProcessingState {
+ final String message;
+
+ PaymentProcessingStateError({required this.message});
+}
diff --git a/comwell_key_app/lib/payment/payment_processing_page.dart b/comwell_key_app/lib/payment/payment_processing_page.dart
new file mode 100644
index 00000000..d1993eb5
--- /dev/null
+++ b/comwell_key_app/lib/payment/payment_processing_page.dart
@@ -0,0 +1,129 @@
+import 'package:adyen_checkout/adyen_checkout.dart';
+import 'package:comwell_key_app/check_out/bloc/check_out_cubit.dart';
+import 'package:comwell_key_app/payment/cubit/payment_cubit.dart';
+import 'package:comwell_key_app/payment/cubit/payment_processing_state.dart';
+import 'package:comwell_key_app/check_out/pages/check_out_error_page.dart';
+import 'package:comwell_key_app/check_out/pages/check_out_success_page.dart';
+import 'package:comwell_key_app/themes/dark_theme.dart';
+import 'package:comwell_key_app/utils/lottie_utils.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:lottie/lottie.dart';
+
+class PaymentProcessingPage extends StatefulWidget {
+ const PaymentProcessingPage({super.key});
+
+ @override
+ State<PaymentProcessingPage> createState() => _PaymentProcessingPageState();
+}
+
+class _PaymentProcessingPageState extends State<PaymentProcessingPage>
+ with SingleTickerProviderStateMixin {
+ LottieComposition? loadingComposition;
+ late final AnimationController animationController;
+
+ @override
+ void initState() {
+ animationController = AnimationController(vsync: this);
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ animationController.dispose();
+ super.dispose();
+ }
+
+ void onAnimationEnd() {
+ playLoading();
+ }
+
+ void playLoading() {
+ loadingComposition?.playBetween(
+ animationController,
+ "spinner",
+ markerEnd: "success",
+ repeat: true,
+ );
+ }
+
+ void playError() async {
+ loadingComposition?.playBetween(
+ animationController,
+ "error",
+ repeat: true,
+ );
+ await Future<void>.delayed(const Duration(seconds: 1));
+ if (mounted) Navigator.of(context).pop();
+ }
+
+ void playSuccess() async {
+ await loadingComposition?.playBetween(
+ animationController,
+ "success",
+ markerEnd: "error",
+ );
+ await Future<void>.delayed(const Duration(seconds: 1));
+ if (mounted) Navigator.of(context).pop();
+ }
+
+ void showAdyenModal(BuildContext context) async {
+ final cubit = context.read<PaymentCubit>();
+ final processingState = cubit.state;
+ dynamic response;
+ if (processingState is! PaymentProcessingStateSessionReceived) return;
+ final paymentConfig = processingState.paymentConfigurations;
+ if (!mounted) return;
+
+ final dropInConfig = paymentConfig.dropInConfiguration;
+ response = await AdyenCheckout.session.startDropIn(
+ dropInConfiguration: dropInConfig,
+ checkout: paymentConfig.sessionCheckout,
+ );
+
+ if (!mounted) return;
+ if (response is PaymentResult) {
+ cubit.onPaymentResult(response);
+ } else {
+ cubit.onUserDismissPaymentPopup();
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final cubit = context.read<PaymentCubit>();
+ return Scaffold(
+ body: Container(
+ alignment: Alignment.center,
+ color: sandColor[80],
+ child: Builder(builder: (context) {
+ final processingState = cubit.state;
+ if (processingState is PaymentProcessingStateSessionReceived) {
+ showAdyenModal(context);
+ }
+ return Lottie.asset(
+ 'assets/animations/load_animation.json',
+ controller: animationController,
+ onLoaded: (composition) {
+ if (loadingComposition == null) {
+ loadingComposition = composition;
+ animationController.duration = composition.duration;
+ switch (cubit.state) {
+ case PaymentProcessingStateConfirmed _:
+ playSuccess();
+ case PaymentProcessingStateError _:
+ playError();
+ default:
+ playLoading();
+ }
+ }
+ },
+ fit: BoxFit.cover,
+ width: 64,
+ height: 64,
+ );
+ }),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/pregistration_repository.dart b/comwell_key_app/lib/pregistration/pregistration_repository.dart
index 01f74c9e..bdaf26d0 100644
--- a/comwell_key_app/lib/pregistration/pregistration_repository.dart
+++ b/comwell_key_app/lib/pregistration/pregistration_repository.dart
@@ -15,7 +15,7 @@ class PreregistrationRepository {
Future<PaymentConfigurations> sessionCheckout(
Amount amount,
- String bookingId,
+ String bookingId,
bool usePoints,
) async {
final response = await _api.createAdyenSession(bookingId, usePoints);
@@ -23,9 +23,11 @@ class PreregistrationRepository {
final sessionResponse = response["sessionResponse"];
final id = sessionResponse["id"] as String;
final sessionData = sessionResponse["sessionData"] as String;
-
+ final payedWithPoints = response["isFullyPaidWithPoints"] as bool;
+ print("qqq payedWithPoints $payedWithPoints");
// Use the server response amount for consistency across all payment methods
- final serverAmount = Amount(value: sessionResponse["amount"]["value"] as int, currency: "DKK");
+ final serverAmount = Amount(
+ value: sessionResponse["amount"]["value"] as int, currency: "DKK");
final session = await AdyenCheckout.session.create(
sessionId: id,
@@ -38,8 +40,8 @@ class PreregistrationRepository {
cardComponentConfiguration:
cardComponentConfiguration(serverAmount, clientKey),
applePayConfiguration:
- _applePayComponentConfiguration(clientKey, serverAmount));
-
+ _applePayComponentConfiguration(clientKey, serverAmount),
+ isFullyPaidWithPoints: payedWithPoints);
}
Future<dynamic> createPreregistration(String confirmationId) async {