6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit 0309d442
Changed files
comwell_key_app/assets/translations/da-DK.json | 9 ++- comwell_key_app/assets/translations/en-US.json | 9 ++- .../services/adyen/stored_payment_method.g.dart | 24 +++--- .../adyen/stored_payment_methods_response.g.dart | 12 +-- .../lib/check_out/bloc/check_out_cubit.dart | 8 +- .../check_out/models/payment_configurations.dart | 14 +++- .../check_out/pages/check_out_processing_page.dart | 2 +- .../payment_cards/bloc/payment_cards_cubit.dart | 77 ++++++++++++++++++ .../payment_cards/bloc/payment_cards_state.dart | 42 ++++++++++ .../lib/payment_cards/components/add_card.dart | 69 ++++++++++++++++ .../payment_cards/components/edit_card_dialog.dart | 85 ++++++++++++++++++++ .../components/remove_card_button.dart | 93 ++++++++++++++++++++++ .../payment_cards/components/save_card_button.dart | 34 ++++++++ .../lib/payment_cards/payment_cards_page.dart | 84 +++++++++++++++++++ .../payment_cards/payment_cards_repository.dart | 23 ++++++ .../pregistration/bloc/preregistration_cubit.dart | 1 + .../lib/pregistration/components/card_item.dart | 85 ++++++++++---------- .../pregistration/pregistration_repository.dart | 58 ++++++++++---- comwell_key_app/lib/profile/profile_page.dart | 2 +- comwell_key_app/lib/routing/app_router.dart | 10 +++ comwell_key_app/lib/routing/app_routes.dart | 1 + .../lib/services/adyen/payment_event_handler.dart | 80 +++++++++++++++++++ .../lib/services/adyen/stored_payment_method.dart | 10 +-- .../adyen/stored_payment_methods_response.dart | 7 +- comwell_key_app/lib/services/api.dart | 80 +++++++++++++++---- .../interceptors/response_handle_interceptor.dart | 27 +++++-- comwell_key_app/lib/themes/comwell_colors.dart | 44 ++++++++++ 27 files changed, 867 insertions(+), 123 deletions(-)
Diff
diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index e88c3b24..48a33646 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -173,5 +173,12 @@
"checkout_page_payment_dialog_confirm": "Ja, check ud nu",
"checkout_page_payment_dialog_cancel": "Nej",
"checkout_page_processing_success_title": "Check-out bekræftet",
- "checkout_page_processing_success_subtitle": "Det check-out er nu bekræftet og du har nu 30 minutter til at forlade dit værelse. Herefter vil du ikke længere kunne bruge dit nøglekort."
+ "checkout_page_processing_success_subtitle": "Det check-out er nu bekræftet og du har nu 30 minutter til at forlade dit værelse. Herefter vil du ikke længere kunne bruge dit nøglekort.",
+ "payment_cards_title": "Betalingskort",
+ "payment_cards_my_cards": "Mine kort",
+ "payment_cards_edit_card_title": "Redigér kort",
+ "payment_cards_confirm_remove_title": "Du er ved at fjerne et betalingskort",
+ "payment_cards_confirm_remove_subtitle": "Dette betalingskort vil ikke længere være tilgængeligt, hvis du sletter det.",
+ "payment_cards_remove_card_button": "Fjern kort",
+ "payment_cards_save_card_button": "Gem kort"
}
\ No newline at end of file
diff --git a/comwell_key_app/assets/translations/en-US.json b/comwell_key_app/assets/translations/en-US.json
index b023f783..6ba07857 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -173,5 +173,12 @@
"checkout_page_payment_dialog_confirm": "Yes, check out now",
"checkout_page_payment_dialog_cancel": "No",
"checkout_page_processing_success_title": "Check-out confirmed",
- "checkout_page_processing_success_subtitle": "You have 30 minutes to leave your room"
+ "checkout_page_processing_success_subtitle": "You have 30 minutes to leave your room",
+ "payment_cards_title": "Payment cards",
+ "payment_cards_my_cards": "My cards",
+ "payment_cards_confirm_remove_title": "You are removing the card",
+ "payment_cards_confirm_remove_subtitle": "This payment card will no longer be usable",
+ "payment_cards_remove_card_button": "Remove card",
+ "payment_cards_edit_card_title": "Edit card",
+ "payment_cards_save_card_button": "Save card"
}
\ No newline at end of file
diff --git a/comwell_key_app/lib/.generated/services/adyen/stored_payment_method.g.dart b/comwell_key_app/lib/.generated/services/adyen/stored_payment_method.g.dart
index ed6ff200..6b2d6b18 100644
--- a/comwell_key_app/lib/.generated/services/adyen/stored_payment_method.g.dart
+++ b/comwell_key_app/lib/.generated/services/adyen/stored_payment_method.g.dart
@@ -8,21 +8,21 @@ part of '../../../services/adyen/stored_payment_method.dart';
StoredPaymentMethod _$StoredPaymentMethodFromJson(Map json) =>
StoredPaymentMethod(
- type: json['Brand'] as String,
- expiryMonth: json['ExpiryMonth'] as String,
- expiryYear: json['ExpiryYear'] as String,
- holderName: json['HolderName'] as String,
- id: json['Id'] as String,
- lastFour: json['LastFour'] as String,
+ brand: json['brand'] as String,
+ expiryMonth: json['expiryMonth'] as String,
+ expiryYear: json['expiryYear'] as String,
+ holderName: json['holderName'] as String,
+ id: json['id'] as String,
+ lastFour: json['lastFour'] as String,
);
Map<String, dynamic> _$StoredPaymentMethodToJson(
StoredPaymentMethod instance) =>
<String, dynamic>{
- 'Brand': instance.type,
- 'ExpiryMonth': instance.expiryMonth,
- 'ExpiryYear': instance.expiryYear,
- 'HolderName': instance.holderName,
- 'Id': instance.id,
- 'LastFour': instance.lastFour,
+ 'brand': instance.brand,
+ 'expiryMonth': instance.expiryMonth,
+ 'expiryYear': instance.expiryYear,
+ 'holderName': instance.holderName,
+ 'id': instance.id,
+ 'lastFour': instance.lastFour,
};
diff --git a/comwell_key_app/lib/.generated/services/adyen/stored_payment_methods_response.g.dart b/comwell_key_app/lib/.generated/services/adyen/stored_payment_methods_response.g.dart
index ce6505d3..8fbae914 100644
--- a/comwell_key_app/lib/.generated/services/adyen/stored_payment_methods_response.g.dart
+++ b/comwell_key_app/lib/.generated/services/adyen/stored_payment_methods_response.g.dart
@@ -8,9 +8,9 @@ part of '../../../services/adyen/stored_payment_methods_response.dart';
StoredPaymentsResponse _$StoredPaymentsResponseFromJson(Map json) =>
StoredPaymentsResponse(
- merchantId: json['MerchantAccount'] as String,
- shopperReference: json['ShopperReference'] as String,
- storedPaymentMethods: (json['StoredPaymentMethods'] as List<dynamic>).map(
+ merchantAccount: json['merchantAccount'] as String,
+ shopperReference: json['shopperReference'] as String,
+ storedPaymentMethods: (json['storedPaymentMethods'] as List<dynamic>).map(
(e) => StoredPaymentMethod.fromJson(
Map<String, dynamic>.from(e as Map))),
);
@@ -18,8 +18,8 @@ StoredPaymentsResponse _$StoredPaymentsResponseFromJson(Map json) =>
Map<String, dynamic> _$StoredPaymentsResponseToJson(
StoredPaymentsResponse instance) =>
<String, dynamic>{
- 'MerchantAccount': instance.merchantId,
- 'ShopperReference': instance.shopperReference,
- 'StoredPaymentMethods':
+ 'merchantAccount': instance.merchantAccount,
+ 'shopperReference': instance.shopperReference,
+ 'storedPaymentMethods':
instance.storedPaymentMethods.map((e) => e.toJson()).toList(),
};
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 0023af73..c90bd31c 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
@@ -113,14 +113,12 @@ class CheckoutCubit extends Cubit<CheckoutState> {
try {
// Price should be in cents/øre, so we multiply with 100
final priceInCents = state.totalPriceAfterDiscount * 100;
- final amount = AdyenAmount(
+ final amount = Amount(
value: priceInCents,
currency: "DKK",
);
- final paymentConfigurations = await preregistrationRepository
- .sessionCheckout(amount, booking.hotelCode);
- emit(state.processingStateUpdated(CheckoutProcessingStateSessionReceived(
- paymentConfigurations: paymentConfigurations)));
+ final paymentConfigurations = await preregistrationRepository.sessionCheckout(amount, booking.hotelCode);
+ emit(state.processingStateUpdated(CheckoutProcessingStateSessionReceived(paymentConfigurations: paymentConfigurations)));
} catch (e) {
emit(state.processingStateUpdated(CheckoutProcessingStateError()));
}
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 909e9702..6df9a6aa 100644
--- a/comwell_key_app/lib/check_out/models/payment_configurations.dart
+++ b/comwell_key_app/lib/check_out/models/payment_configurations.dart
@@ -1,11 +1,17 @@
import 'package:adyen_checkout/adyen_checkout.dart';
class PaymentConfigurations {
-
final SessionCheckout sessionCheckout;
final GooglePayComponentConfiguration googlePayConfiguration;
- final DropInConfiguration cardConfiguration;
+ final DropInConfiguration dropInConfiguration;
+ final CardComponentConfiguration cardComponentConfiguration;
final ApplePayComponentConfiguration applePayConfiguration;
- PaymentConfigurations({required this.sessionCheckout, required this.googlePayConfiguration, required this.cardConfiguration, required this.applePayConfiguration});
-}
\ No newline at end of file
+ PaymentConfigurations({
+ required this.cardComponentConfiguration,
+ required this.sessionCheckout,
+ required this.googlePayConfiguration,
+ required this.dropInConfiguration,
+ required this.applePayConfiguration,
+ });
+}
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 f6adb8f7..d9a27890 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
@@ -72,7 +72,7 @@ class _CheckOutProcessingPageState extends State<CheckOutProcessingPage>
final paymentConfig = processingState.paymentConfigurations;
if (!mounted) return;
if (paymentMethod == CheckoutPaymentMethod.creditCard) {
- final dropInConfig = paymentConfig.cardConfiguration;
+ final dropInConfig = paymentConfig.dropInConfiguration;
response = await AdyenCheckout.session.startDropIn(
dropInConfiguration: dropInConfig,
checkout: paymentConfig.sessionCheckout,
diff --git a/comwell_key_app/lib/payment_cards/bloc/payment_cards_cubit.dart b/comwell_key_app/lib/payment_cards/bloc/payment_cards_cubit.dart
new file mode 100644
index 00000000..c229cb50
--- /dev/null
+++ b/comwell_key_app/lib/payment_cards/bloc/payment_cards_cubit.dart
@@ -0,0 +1,77 @@
+import 'package:adyen_checkout/adyen_checkout.dart';
+import 'package:bloc/bloc.dart';
+import 'package:comwell_key_app/check_out/models/payment_configurations.dart';
+import 'package:comwell_key_app/overview/repository/overview_repository.dart';
+import 'package:comwell_key_app/payment_cards/bloc/payment_cards_state.dart';
+import 'package:comwell_key_app/payment_cards/payment_cards_repository.dart';
+import 'package:comwell_key_app/pregistration/pregistration_repository.dart';
+import 'package:comwell_key_app/profile_settings/repostiory/profile_settings_repository.dart';
+import 'package:comwell_key_app/services/adyen/payment_event_handler.dart';
+import 'package:comwell_key_app/services/api.dart';
+import 'package:comwell_key_app/utils/locator.dart';
+
+class PaymentCardsCubit extends Cubit<PaymentCardsState> {
+ final PaymentCardsRepository _paymentCardsRepository =
+ PaymentCardsRepository();
+ final PreregistrationRepository _preregistrationRepository =
+ locator<PreregistrationRepository>();
+ final ProfileSettingsRepository profileSettingsRepository =
+ locator<ProfileSettingsRepository>();
+ final Api _api = Api();
+ late PaymentConfigurations paymentConfigurations;
+
+ PaymentCardsCubit() : super(PaymentCardsState.initial()) {
+ init();
+ }
+
+ Future<PaymentConfigurations> fetchPaymentConfiguration() async {
+ final session = await _preregistrationRepository.sessionCheckout(
+ Amount(currency: "DKK", value: 0), "CBO");
+ return session;
+ }
+
+ void init() async {
+ try {
+ final cards = await _paymentCardsRepository.getCards();
+ paymentConfigurations = await fetchPaymentConfiguration();
+ emit(state.cardsFetched(cards));
+ } catch (e) {
+ emit(state.cardsFetchedError());
+ }
+ }
+
+ Future<void> onPaymentResult(PaymentResult result) async {
+ switch (result) {
+ case PaymentAdvancedFinished():
+ case PaymentSessionFinished():
+ init();
+ break;
+ case PaymentCancelledByUser():
+ case PaymentError():
+ emit(state.cardsFetchedError());
+ }
+ }
+
+ Checkout advancedCheckout() {
+ return AdvancedCheckout(
+ onSubmit: (data, [extra]) async {
+ try {
+ final user = await profileSettingsRepository.fetchProfileSettings();
+ final shopperRef = user?.shopperReference ?? "Test reference";
+ final response = await _api.submitPayment(data, shopperRef);
+ return PaymentEventHandler().handleResponse(jsonResponse: response);
+ } catch (e) {
+ return Error(errorMessage: "$e");
+ }
+ },
+ onAdditionalDetails: (data) async {
+ final response = await _api.postPaymentsDetails(data);
+ return PaymentEventHandler().handleResponse(jsonResponse: response);
+ },
+ );
+ }
+
+ void onRemoveCard(String cardId) {
+
+ }
+}
diff --git a/comwell_key_app/lib/payment_cards/bloc/payment_cards_state.dart b/comwell_key_app/lib/payment_cards/bloc/payment_cards_state.dart
new file mode 100644
index 00000000..ded62dd1
--- /dev/null
+++ b/comwell_key_app/lib/payment_cards/bloc/payment_cards_state.dart
@@ -0,0 +1,42 @@
+import 'package:comwell_key_app/services/adyen/stored_payment_method.dart';
+import 'package:equatable/equatable.dart';
+
+class PaymentCardsState extends Equatable {
+ final bool isLoading;
+ final bool hasError;
+ final Iterable<StoredPaymentMethod> cards;
+
+ const PaymentCardsState._({
+ required this.cards,
+ required this.isLoading,
+ required this.hasError,
+ });
+
+ PaymentCardsState.initial()
+ : cards = [],
+ isLoading = true,
+ hasError = false;
+
+ PaymentCardsState cardsFetched(Iterable<StoredPaymentMethod> cards) {
+ return _copyWith(cards: cards, isLoading: false);
+ }
+
+ PaymentCardsState cardsFetchedError() =>
+ _copyWith(isLoading: false, hasError: true);
+
+ PaymentCardsState _copyWith({
+ Iterable<StoredPaymentMethod>? cards,
+ bool? isLoading,
+ bool? hasError,
+ }) {
+ return PaymentCardsState._(
+ cards: cards ?? this.cards,
+ isLoading: isLoading ?? this.isLoading,
+ hasError: hasError ?? this.hasError,
+ );
+ }
+
+ @override
+ List<Object?> get props => [isLoading, hasError, cards];
+
+}
diff --git a/comwell_key_app/lib/payment_cards/components/add_card.dart b/comwell_key_app/lib/payment_cards/components/add_card.dart
new file mode 100644
index 00000000..61a5d2a0
--- /dev/null
+++ b/comwell_key_app/lib/payment_cards/components/add_card.dart
@@ -0,0 +1,69 @@
+import 'package:adyen_checkout/adyen_checkout.dart';
+import 'package:comwell_key_app/payment_cards/bloc/payment_cards_cubit.dart';
+import 'package:comwell_key_app/pregistration/models/add_card_payment_method.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+
+class AddCard extends StatelessWidget {
+ const AddCard({super.key});
+
+ Future<void> showPaymentDialog(BuildContext context) async {
+ final cubit = context.read<PaymentCardsCubit>();
+ // To add a card, users needs to perform a zero-amount payment
+ final paymentMethodConfig = AddCardPaymentMethod(
+ brands: [CardType.mc, CardType.visa], name: "Cards", type: "scheme");
+ await showModalBottomSheet<void>(
+ isDismissible: false,
+ isScrollControlled: true,
+ context: context,
+ builder: (BuildContext context) {
+ return SafeArea(
+ child: Padding(
+ padding: MediaQuery.of(context).viewInsets,
+ child: AdyenCardComponent(
+ configuration:
+ cubit.paymentConfigurations.cardComponentConfiguration,
+ paymentMethod: paymentMethodConfig.toJson(),
+ checkout: cubit.advancedCheckout(),
+ onPaymentResult: cubit.onPaymentResult,
+ ),
+ ));
+ },
+ );
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return InkWell(
+ onTap: () async {
+ await showPaymentDialog(context);
+ },
+ child: Container(
+ decoration: BoxDecoration(
+ border: Border.all(color: colorDivider),
+ ),
+ padding: const EdgeInsets.all(12),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Text(
+ "preregistration_payment_add_card".tr(),
+ style: Theme.of(context).textTheme.bodyMedium,
+ ),
+ const SizedBox(width: 12),
+ SvgPicture.asset("assets/icons/visa.svg"),
+ const SizedBox(width: 4),
+ SvgPicture.asset("assets/icons/mastercard.svg"),
+ const SizedBox(width: 4),
+ SvgPicture.asset("assets/icons/maestro.svg"),
+ const Expanded(child: SizedBox()),
+ SvgPicture.asset("assets/icons/ic_plus.svg"),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/payment_cards/components/edit_card_dialog.dart b/comwell_key_app/lib/payment_cards/components/edit_card_dialog.dart
new file mode 100644
index 00000000..3b7c6857
--- /dev/null
+++ b/comwell_key_app/lib/payment_cards/components/edit_card_dialog.dart
@@ -0,0 +1,85 @@
+import 'package:comwell_key_app/payment_cards/components/remove_card_button.dart';
+import 'package:comwell_key_app/payment_cards/components/save_card_button.dart';
+import 'package:comwell_key_app/services/adyen/stored_payment_method.dart';
+import 'package:comwell_key_app/themes/comwell_colors.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+class EditCardDialog extends StatelessWidget {
+ final StoredPaymentMethod storedPaymentMethod;
+ final void Function() onRemoveCard;
+
+ const EditCardDialog({
+ super.key,
+ required this.storedPaymentMethod,
+ required this.onRemoveCard,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text("payment_cards_edit_card_title".tr(),
+ style: Theme.of(context).textTheme.headlineLarge),
+ const SizedBox(height: 48),
+ Text(storedPaymentMethod.holderName,
+ style: Theme.of(context).textTheme.headlineMedium),
+ const SizedBox(height: 20),
+ TextField(
+ style: Theme.of(context).textTheme.bodySmall,
+ decoration: const InputDecoration(
+ hintText: "Name on card",
+ border:
+ OutlineInputBorder(borderSide: BorderSide(color: colorDivider)),
+ ),
+ ),
+ const SizedBox(height: 4),
+ TextField(
+ style: Theme.of(context).textTheme.bodySmall,
+ decoration: const InputDecoration(
+ hintText: "Card number",
+ border:
+ OutlineInputBorder(borderSide: BorderSide(color: colorDivider)),
+ ),
+ ),
+ const SizedBox(height: 4),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Expanded(
+ child: TextField(
+ style: Theme.of(context).textTheme.bodySmall,
+ decoration: const InputDecoration(
+ hintText: "Expiry date",
+ border: OutlineInputBorder(
+ borderSide: BorderSide(color: colorDivider)),
+ ),
+ ),
+ ),
+ const SizedBox(width: 4),
+ Expanded(
+ child: TextField(
+ style: Theme.of(context).textTheme.bodySmall,
+ decoration: const InputDecoration(
+ hintText: "CVC",
+ border: OutlineInputBorder(
+ borderSide: BorderSide(color: colorDivider)),
+ ),
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(height: 34),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ RemoveCardButton(onRemoveCard: () {
+ onRemoveCard();
+ }),
+ ],
+ ),
+ ],
+ );
+ }
+}
diff --git a/comwell_key_app/lib/payment_cards/components/remove_card_button.dart b/comwell_key_app/lib/payment_cards/components/remove_card_button.dart
new file mode 100644
index 00000000..7455dd7e
--- /dev/null
+++ b/comwell_key_app/lib/payment_cards/components/remove_card_button.dart
@@ -0,0 +1,93 @@
+import 'package:comwell_key_app/themes/comwell_colors.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+
+class RemoveCardButton extends StatelessWidget {
+ final void Function() onRemoveCard;
+
+ const RemoveCardButton({super.key, required this.onRemoveCard});
+
+ @override
+ Widget build(BuildContext context) {
+ return InkWell(
+ onTap: () async {
+ final response = await showDialog<dynamic>(
+ context: context,
+ builder: (context) {
+ return Dialog(
+ child: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ "payment_cards_confirm_remove_title".tr(),
+ style: Theme.of(context).textTheme.headlineMedium,
+ ),
+ const SizedBox(height: 32),
+ Text(
+ "payment_cards_confirm_remove_subtitle".tr(),
+ style: Theme.of(context)
+ .textTheme
+ .bodySmall
+ ?.copyWith(
+ color: Colors.black.withOpacity(0.65))),
+ MaterialButton(
+ minWidth: double.infinity,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(30)),
+ color: sandColor[80],
+ onPressed: () {
+ context.pop(true);
+ },
+ child: Text(
+ "generic_confirm".tr(),
+ style: const TextStyle(color: Colors.white),
+ ),
+ ),
+ const SizedBox(height: 8),
+ MaterialButton(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(30),
+ side: const BorderSide(color: colorDivider)),
+ minWidth: double.infinity,
+ child: Text(
+ "cancel".tr(),
+ ),
+ onPressed: () {
+ context.pop(false);
+ }),
+ ],
+ ),
+ ),
+ );
+ });
+ if (response is bool && response == true) {
+ onRemoveCard();
+ if (context.mounted) {
+ context.pop();
+ }
+ }
+ },
+ child: Container(
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: colorDivider,
+ ),
+ borderRadius: BorderRadius.circular(30),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 32),
+ child: Text(
+ "payment_cards_remove_card_button".tr(),
+ style: Theme.of(context)
+ .textTheme
+ .bodySmall
+ ?.copyWith(color: colorError),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/payment_cards/components/save_card_button.dart b/comwell_key_app/lib/payment_cards/components/save_card_button.dart
new file mode 100644
index 00000000..e132f84f
--- /dev/null
+++ b/comwell_key_app/lib/payment_cards/components/save_card_button.dart
@@ -0,0 +1,34 @@
+import 'package:comwell_key_app/themes/comwell_colors.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+
+class SaveCardButton extends StatelessWidget {
+ final void Function() onSaveCard;
+
+ const SaveCardButton({super.key, required this.onSaveCard});
+
+ @override
+ Widget build(BuildContext context) {
+ return InkWell(
+ onTap: () async {},
+ child: Container(
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: colorDivider,
+ ),
+ borderRadius: BorderRadius.circular(30),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 32),
+ child: Text(
+ "payment_cards_remove_card_button".tr(),
+ style: Theme.of(context)
+ .textTheme
+ .bodySmall,
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/payment_cards/payment_cards_page.dart b/comwell_key_app/lib/payment_cards/payment_cards_page.dart
new file mode 100644
index 00000000..a32bafa3
--- /dev/null
+++ b/comwell_key_app/lib/payment_cards/payment_cards_page.dart
@@ -0,0 +1,84 @@
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/payment_cards/bloc/payment_cards_state.dart';
+import 'package:comwell_key_app/payment_cards/components/add_card.dart';
+import 'package:comwell_key_app/payment_cards/components/edit_card_dialog.dart';
+import 'package:comwell_key_app/payment_cards/components/remove_card_button.dart';
+import 'package:comwell_key_app/pregistration/components/card_item.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../themes/light_theme.dart';
+import 'bloc/payment_cards_cubit.dart';
+
+class PaymentCardsPage extends StatelessWidget {
+ const PaymentCardsPage({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder<PaymentCardsCubit, PaymentCardsState>(
+ builder: (context, state) {
+ final cubit = context.read<PaymentCardsCubit>();
+ final cards = cubit.state.cards;
+ return Scaffold(
+ appBar: const ComwellAppBar(shouldShowProfileButton: false),
+ body: Builder(builder: (context) {
+ if (cubit.state.isLoading) {
+ return const Center(child: CircularProgressIndicator());
+ }
+ if (cubit.state.hasError) {
+ return const Center(child: Text('Error fetching cards'));
+ }
+ return Center(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(height: 40),
+ Text(
+ "payment_cards_title".tr(),
+ style: Theme.of(context).textTheme.headlineLarge,
+ ),
+ const SizedBox(height: 40),
+ Text("payment_cards_my_cards".tr(),
+ style: Theme.of(context).textTheme.headlineMedium),
+ const SizedBox(height: 20),
+ ...cards.map(
+ (card) => Container(
+ decoration: BoxDecoration(
+ border: Border.all(color: colorDivider),
+ ),
+ padding: const EdgeInsets.all(12),
+ child: CardItem(
+ paymentMethod: card,
+ onClick: () {
+ showModalBottomSheet<void>(
+ context: context,
+ builder: (context) {
+ return Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: EditCardDialog(
+ storedPaymentMethod: card,
+ onRemoveCard: () {
+ cubit.onRemoveCard(card.id);
+ },
+ ),
+ );
+ },
+ );
+ },
+ ),
+ ),
+ ),
+ const SizedBox(height: 12),
+ const AddCard()
+ ],
+ ),
+ ),
+ );
+ }),
+ );
+ });
+ }
+}
diff --git a/comwell_key_app/lib/payment_cards/payment_cards_repository.dart b/comwell_key_app/lib/payment_cards/payment_cards_repository.dart
new file mode 100644
index 00000000..747d649b
--- /dev/null
+++ b/comwell_key_app/lib/payment_cards/payment_cards_repository.dart
@@ -0,0 +1,23 @@
+import 'package:comwell_key_app/services/adyen/stored_payment_method.dart';
+import 'package:comwell_key_app/services/api.dart';
+
+class PaymentCardsRepository {
+ final _api = Api();
+
+ Future<Iterable<StoredPaymentMethod>> getCards() async {
+ final cards = await _api.getPaymentMethods();
+ return cards.storedPaymentMethods;
+ }
+
+ Future<void> removeCard(StoredPaymentMethod card) async {
+
+ }
+
+ Future<void> addCard() async {
+
+ }
+
+ Future<void> updateCard(StoredPaymentMethod card) async {
+
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/bloc/preregistration_cubit.dart b/comwell_key_app/lib/pregistration/bloc/preregistration_cubit.dart
index fc05742e..9fb08f85 100644
--- a/comwell_key_app/lib/pregistration/bloc/preregistration_cubit.dart
+++ b/comwell_key_app/lib/pregistration/bloc/preregistration_cubit.dart
@@ -1,4 +1,5 @@
+import 'package:adyen_checkout/src/common/model/payment_result.dart';
import 'package:bloc/bloc.dart';
import 'package:comwell_key_app/pregistration/bloc/preregistration_state.dart';
import 'package:comwell_key_app/pregistration/preregistration_flow.dart';
diff --git a/comwell_key_app/lib/pregistration/components/card_item.dart b/comwell_key_app/lib/pregistration/components/card_item.dart
index 6ffecbcd..1e45fa8f 100644
--- a/comwell_key_app/lib/pregistration/components/card_item.dart
+++ b/comwell_key_app/lib/pregistration/components/card_item.dart
@@ -7,55 +7,60 @@ import 'package:flutter_svg/flutter_svg.dart';
class CardItem extends StatelessWidget {
final StoredPaymentMethod paymentMethod;
final bool isSelected;
+ final VoidCallback? onClick;
const CardItem({
super.key,
required this.paymentMethod,
+ this.onClick,
this.isSelected = false,
});
@override
Widget build(BuildContext context) {
- return Row(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- PaymentCardImage(cardType: CardType.fromString(paymentMethod.type)),
- const SizedBox(width: 12),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- paymentMethod.holderName,
- style: Theme.of(context).textTheme.bodySmall,
- ),
- Row(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- ..."**** **** **** ".characters.map((char) {
- if (char == '*') {
- return Padding(
- padding: const EdgeInsets.symmetric(horizontal: 1.0),
- child: Container(
- width: 5,
- height: 5,
- decoration: const BoxDecoration(
- shape: BoxShape.circle, color: Colors.black),
- ),
- );
- }
- return const SizedBox(width: 8);
- }),
- Text(
- paymentMethod.lastFour,
- style: Theme.of(context).textTheme.bodyMedium,
- )
- ],
- ),
- ],
- ),
- const Expanded(child: SizedBox()),
- if (isSelected) SvgPicture.asset("assets/icons/ic_checkmark.svg")
- ],
+ return InkWell(
+ onTap: onClick,
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ PaymentCardImage(cardType: CardType.fromString(paymentMethod.brand)),
+ const SizedBox(width: 12),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ paymentMethod.holderName,
+ style: Theme.of(context).textTheme.bodySmall,
+ ),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ ..."**** **** **** ".characters.map((char) {
+ if (char == '*') {
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 1.0),
+ child: Container(
+ width: 5,
+ height: 5,
+ decoration: const BoxDecoration(
+ shape: BoxShape.circle, color: Colors.black),
+ ),
+ );
+ }
+ return const SizedBox(width: 8);
+ }),
+ Text(
+ paymentMethod.lastFour,
+ style: Theme.of(context).textTheme.bodyMedium,
+ )
+ ],
+ ),
+ ],
+ ),
+ const Expanded(child: SizedBox()),
+ if (isSelected) SvgPicture.asset("assets/icons/ic_checkmark.svg")
+ ],
+ ),
);
}
}
diff --git a/comwell_key_app/lib/pregistration/pregistration_repository.dart b/comwell_key_app/lib/pregistration/pregistration_repository.dart
index 4144873b..48c8af10 100644
--- a/comwell_key_app/lib/pregistration/pregistration_repository.dart
+++ b/comwell_key_app/lib/pregistration/pregistration_repository.dart
@@ -1,7 +1,6 @@
import 'package:adyen_checkout/adyen_checkout.dart';
import 'package:comwell_key_app/check_out/models/payment_configurations.dart';
import 'package:comwell_key_app/profile_settings/repostiory/profile_settings_repository.dart';
-import 'package:comwell_key_app/services/adyen/adyen_amount.dart';
import 'package:comwell_key_app/services/adyen/stored_payment_method.dart';
import 'package:comwell_key_app/services/api.dart';
import 'package:comwell_key_app/utils/locator.dart';
@@ -13,33 +12,52 @@ class PreregistrationRepository {
PreregistrationRepository();
- Future<PaymentConfigurations> sessionCheckout(AdyenAmount amount, String hotelCode) async {
+ Future<PaymentConfigurations> sessionCheckout(
+ Amount amount,
+ String hotelCode,
+ ) async {
final response = await _api.createAdyenSession(amount, hotelCode);
- final clientKey = response["ClientKey"] as String;
- final sessionResponse = response["SessionResponse"];
- final id = sessionResponse["Id"] as String;
- final sessionData = sessionResponse["SessionData"] as String;
+ final clientKey = response["clientKey"] as String;
+ final sessionResponse = response["sessionResponse"];
+ final id = sessionResponse["id"] as String;
+ final sessionData = sessionResponse["sessionData"] as String;
final session = await AdyenCheckout.session.create(
sessionId: id,
sessionData: sessionData,
- configuration: cardComponentConfiguration(amount, clientKey));
+ configuration: dropInConfiguration(amount, clientKey));
return PaymentConfigurations(
sessionCheckout: session,
googlePayConfiguration: _getGooglePayComponentConfig(clientKey),
- cardConfiguration: cardComponentConfiguration(amount, clientKey),
- applePayConfiguration: _applePayComponentConfiguration(clientKey, amount));
+ dropInConfiguration: dropInConfiguration(amount, clientKey),
+ cardComponentConfiguration:
+ cardComponentConfiguration(amount, clientKey),
+ applePayConfiguration:
+ _applePayComponentConfiguration(clientKey, amount));
}
- DropInConfiguration cardComponentConfiguration(
- AdyenAmount amount, String clientKey) {
+ CardComponentConfiguration cardComponentConfiguration(
+ Amount amount,
+ String clientKey,
+ ) {
+ return CardComponentConfiguration(
+ environment: Environment.test,
+ amount: amount,
+ cardConfiguration: const CardConfiguration(showStorePaymentField: true),
+ clientKey: clientKey,
+ countryCode: "DK",
+ );
+ }
+
+ DropInConfiguration dropInConfiguration(Amount amount, String clientKey) {
// TODO: missing endpoint to retrieve client key
return DropInConfiguration(
environment: Environment.test,
clientKey: clientKey,
countryCode: "DK",
+ skipListWhenSinglePaymentMethod: true,
googlePayConfiguration: _googlePayConfiguration,
applePayConfiguration: _getApplePlayConfig(amount),
- cardConfiguration: null,
+ cardConfiguration: const CardConfiguration(showStorePaymentField: true),
paymentMethodNames: {
"scheme": "Credit card",
},
@@ -47,10 +65,13 @@ class PreregistrationRepository {
}
GooglePayConfiguration get _googlePayConfiguration =>
- const GooglePayConfiguration(googlePayEnvironment: GooglePayEnvironment.test);
+ const GooglePayConfiguration(
+ googlePayEnvironment: GooglePayEnvironment.test,
+ );
GooglePayComponentConfiguration _getGooglePayComponentConfig(
- String clientKey) {
+ String clientKey,
+ ) {
return GooglePayComponentConfiguration(
environment: Environment.test,
countryCode: "DK",
@@ -59,7 +80,10 @@ class PreregistrationRepository {
);
}
- ApplePayComponentConfiguration _applePayComponentConfiguration(String clientKey, AdyenAmount amount) {
+ ApplePayComponentConfiguration _applePayComponentConfiguration(
+ String clientKey,
+ Amount amount,
+ ) {
return ApplePayComponentConfiguration(
environment: Environment.test,
countryCode: "DK",
@@ -68,7 +92,7 @@ class PreregistrationRepository {
);
}
- ApplePayConfiguration _getApplePlayConfig(AdyenAmount amount) {
+ ApplePayConfiguration _getApplePlayConfig(Amount amount) {
return ApplePayConfiguration(
merchantId: "merchant.ComwellHotelsECOM",
merchantName: "Comwell",
@@ -93,5 +117,5 @@ class PreregistrationRepository {
holderName: "holder name",
id: "id $i",
lastFour: "$i$i$i$i",
- type: "visa"));
+ brand: "visa"));
}
diff --git a/comwell_key_app/lib/profile/profile_page.dart b/comwell_key_app/lib/profile/profile_page.dart
index 648707cb..88e7af32 100644
--- a/comwell_key_app/lib/profile/profile_page.dart
+++ b/comwell_key_app/lib/profile/profile_page.dart
@@ -140,7 +140,7 @@ class ProfilePage extends StatelessWidget {
text: 'payment_card_profile_menu'.tr(),
trailingIcon: Icons.chevron_right,
onTap: () {
- // Navigate to card
+ context.pushNamed(AppRoutes.paymentCards.name);
},
),
const Padding(
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index f81a9783..3032217f 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -18,6 +18,8 @@ import 'package:comwell_key_app/login/login_page.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/overview/overview_page.dart';
import 'package:comwell_key_app/overview/past_cancelled_booking_detail_page.dart';
+import 'package:comwell_key_app/payment_cards/bloc/payment_cards_cubit.dart';
+import 'package:comwell_key_app/payment_cards/payment_cards_page.dart';
import 'package:comwell_key_app/pregistration/preregistration_flow.dart';
import 'package:comwell_key_app/profile/profile_page.dart';
import 'package:comwell_key_app/profile_settings/components/change_password_modal.dart';
@@ -205,6 +207,14 @@ GoRouter goRouter(AuthenticationBloc authBloc) {
),
],
),
+ GoRoute(
+ path: "/${AppRoutes.paymentCards.name}",
+ name: AppRoutes.paymentCards.name,
+ builder: (context, state) {
+ return BlocProvider(
+ create: (context) => PaymentCardsCubit(),
+ child: const PaymentCardsPage());
+ }),
GoRoute(
path: "/login",
name: AppRoutes.login.name,
diff --git a/comwell_key_app/lib/routing/app_routes.dart b/comwell_key_app/lib/routing/app_routes.dart
index 4d620d03..dc9b9a99 100644
--- a/comwell_key_app/lib/routing/app_routes.dart
+++ b/comwell_key_app/lib/routing/app_routes.dart
@@ -24,4 +24,5 @@ enum AppRoutes {
parking,
houseKeeping,
checkOut,
+ paymentCards,
}
diff --git a/comwell_key_app/lib/services/adyen/payment_event_handler.dart b/comwell_key_app/lib/services/adyen/payment_event_handler.dart
new file mode 100644
index 00000000..38762a8d
--- /dev/null
+++ b/comwell_key_app/lib/services/adyen/payment_event_handler.dart
@@ -0,0 +1,80 @@
+import 'package:adyen_checkout/adyen_checkout.dart';
+import 'package:comwell_key_app/utils/json.dart';
+
+class PaymentEventHandler {
+ //Response keys
+ static const errorCodeKey = "errorCode";
+ static const resultCodeKey = "resultCode";
+ static const actionKey = "action";
+ static const messageKey = "message";
+ static const refusalReasonKey = "refusalReason";
+
+ PaymentEvent handleResponse({
+ required Json jsonResponse,
+ Json updatedPaymentMethodsJson = const {},
+ }) {
+ if (_isError(jsonResponse)) {
+ final message = jsonResponse[messageKey] as String?;
+ final reason = jsonResponse[refusalReasonKey] as String;
+ return Error(
+ errorMessage: message,
+ reason: message ?? reason,
+ dismissDropIn: true,
+ );
+ }
+
+ if (_isRefusedInPartialPaymentFlow(jsonResponse)) {
+ return Error(
+ errorMessage: "Payment is refused",
+ reason: "Refused",
+ dismissDropIn: true,
+ );
+ }
+
+ if (_isAction(jsonResponse)) {
+ return Action(actionResponse: jsonResponse[actionKey] as Json);
+ }
+
+ if (_isNonFullyPaidOrder(jsonResponse) &&
+ updatedPaymentMethodsJson.isNotEmpty) {
+ return Update(
+ orderJson: jsonResponse["order"] as Json,
+ paymentMethodsJson: updatedPaymentMethodsJson,
+ );
+ }
+
+ if (jsonResponse.containsKey(resultCodeKey)) {
+ return Finished(resultCode: jsonResponse[resultCodeKey] as String);
+ }
+
+ return Finished(resultCode: "EMPTY");
+ }
+
+ bool _isError(Json jsonResponse) {
+ final hasErrorCodeKey = jsonResponse.containsKey(errorCodeKey);
+ final hasErrorResultCode = (jsonResponse[resultCodeKey] as String?)
+ ?.toUpperCase()
+ .contains(ResultCode.error.name.toUpperCase()) ??
+ false;
+ return hasErrorCodeKey || hasErrorResultCode;
+ }
+
+ bool _isRefusedInPartialPaymentFlow(Json jsonResponse) =>
+ _isRefused(jsonResponse) && _isNonFullyPaidOrder(jsonResponse);
+
+ bool _isRefused(Json jsonResponse) => jsonResponse[resultCodeKey]
+ .toString()
+ .toUpperCase()
+ .contains(ResultCode.refused.name.toUpperCase());
+
+ bool _isAction(Json jsonResponse) => jsonResponse.containsKey(actionKey);
+
+ bool _isNonFullyPaidOrder(Json jsonResponse) {
+ if (jsonResponse.containsKey("order")) {
+ final remainingAmount = jsonResponse["order"]["remainingAmount"]["value"] as num;
+ return remainingAmount > 0;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/comwell_key_app/lib/services/adyen/stored_payment_method.dart b/comwell_key_app/lib/services/adyen/stored_payment_method.dart
index 50a59d36..4a3f4774 100644
--- a/comwell_key_app/lib/services/adyen/stored_payment_method.dart
+++ b/comwell_key_app/lib/services/adyen/stored_payment_method.dart
@@ -6,21 +6,15 @@ part '../../.generated/services/adyen/stored_payment_method.g.dart';
@JsonSerializable()
class StoredPaymentMethod extends Equatable {
- @JsonKey(name: "Brand")
- final String type;
- @JsonKey(name: "ExpiryMonth")
+ final String brand;
final String expiryMonth;
- @JsonKey(name: "ExpiryYear")
final String expiryYear;
- @JsonKey(name: "HolderName")
final String holderName;
- @JsonKey(name: "Id")
final String id;
- @JsonKey(name: "LastFour")
final String lastFour;
const StoredPaymentMethod({
- required this.type,
+ required this.brand,
required this.expiryMonth,
required this.expiryYear,
required this.holderName,
diff --git a/comwell_key_app/lib/services/adyen/stored_payment_methods_response.dart b/comwell_key_app/lib/services/adyen/stored_payment_methods_response.dart
index 0998324b..a53e2a07 100644
--- a/comwell_key_app/lib/services/adyen/stored_payment_methods_response.dart
+++ b/comwell_key_app/lib/services/adyen/stored_payment_methods_response.dart
@@ -6,14 +6,11 @@ part '../../.generated/services/adyen/stored_payment_methods_response.g.dart';
@JsonSerializable()
class StoredPaymentsResponse {
- @JsonKey(name: "MerchantAccount")
- final String merchantId;
- @JsonKey(name: "ShopperReference")
+ final String merchantAccount;
final String shopperReference;
- @JsonKey(name: "StoredPaymentMethods")
final Iterable<StoredPaymentMethod> storedPaymentMethods;
- StoredPaymentsResponse({required this.merchantId, required this.shopperReference, required this.storedPaymentMethods});
+ StoredPaymentsResponse({required this.merchantAccount, required this.shopperReference, required this.storedPaymentMethods});
factory StoredPaymentsResponse.fromJson(Json json) => _$StoredPaymentsResponseFromJson(json);
diff --git a/comwell_key_app/lib/services/api.dart b/comwell_key_app/lib/services/api.dart
index ae981b90..a4a63032 100644
--- a/comwell_key_app/lib/services/api.dart
+++ b/comwell_key_app/lib/services/api.dart
@@ -1,8 +1,8 @@
import 'dart:convert';
+import 'package:adyen_checkout/adyen_checkout.dart';
import 'package:comwell_key_app/hotel_information/models/hotel.dart';
import 'package:comwell_key_app/profile_settings/model/user.dart';
-import 'package:comwell_key_app/services/adyen/adyen_amount.dart';
import 'package:comwell_key_app/services/http_client.dart';
import 'package:comwell_key_app/utils/json.dart';
import 'package:dio/dio.dart';
@@ -34,28 +34,42 @@ class Api {
return StoredPaymentsResponse.fromJson(response.data!);
}
- Future<dynamic> createAdyenSession(AdyenAmount amount, String hotelCode) async {
+ Future<dynamic> createAdyenSession(Amount amount, String hotelCode) async {
final body = {
"hotelCode": hotelCode,
"amount": amount.value,
"returnUrl": "adyencheckout://com.comwell.phoenix.test/adyenPayment",
};
final json = jsonEncode(body);
- final response = await dio.post<dynamic>(
- "/Payment/v1/CreateAdyenSession", data: json);
+ final response =
+ await dio.post<dynamic>("/Payment/v1/CreateAdyenSession", data: json);
return response.data;
}
- Future<String> createEndpointRegistration() async {
- final response = await dio.post<String>(
- '/keys/v1/CreateEndpointRegistration');
- final json = jsonDecode(response.data!) as Map<String, dynamic>;
- return json["InvitationCode"]! as String;
- }
-
- Future<void> provisionKey(String bookingId) async {
- await dio.post<void>(
- '/keys/v1/ProvisionKey', data: {'bookingId': bookingId});
+ Future<Json> submitPayment(Json paymentResult, String shopperReference) async {
+ final Json headers = {
+ "content-type": "application/json",
+ "x-API-key":
+ "AQEohmfuXNWTK0Qc+iSTnWkvouiXYIRZCJ9ZsI49DtvZ0d3gjdIA7pissxDBXVsNvuR83LVYjEgiTGAH-4HQnMZXxLZfhge7EdwYZZW0ynntChj41ziiKl6D1Glo=-.\$>;9&L_t@^g7[IR"
+ };
+ final Map<String, dynamic> data = {
+ "shopperReference": "Test reference",
+ "amount": {"value:": 0, "currency": "DKK"},
+ "countryCode": "DK",
+ "merchantAccount": "ComwellHotelsECOM",
+ "returnUrl": "comwell://",
+ "reference": "flutter-test_${DateTime.now().millisecondsSinceEpoch}",
+ "channel": "iOS",
+ };
+ data.addAll(paymentResult);
+ data.remove("storePaymentMethod");
+ final response =
+ await dio.post<Json>("https://checkout-test.adyen.com/v71/payments",
+ data: data,
+ options: Options(
+ headers: headers,
+ ));
+ return response.data!;
}
Future<dynamic> fetchProfileSettings() async {
@@ -110,4 +124,42 @@ class Api {
await Future<void>.delayed(const Duration(seconds: 2));
// TODO implement
}
+
+ // ADYEN ENDPOINTS - Should be refactored to backend
+ Future<Json> postPaymentsDetails(Json body) async {
+ final Json headers = {
+ "content-type": "application/json",
+ "x-API-key":
+ "AQEohmfuXNWTK0Qc+iSTnWkvouiXYIRZCJ9ZsI49DtvZ0d3gjdIA7pissxDBXVsNvuR83LVYjEgiTGAH-4HQnMZXxLZfhge7EdwYZZW0ynntChj41ziiKl6D1Glo=-.\$>;9&L_t@^g7[IR"
+ };
+ final Map<String, dynamic> data = {
+ "shopperReference": "Test reference",
+ "amount": {"value:": 0, "currency": "DKK"},
+ "countryCode": "DK",
+ "merchantAccount": "ComwellHotelsECOM",
+ "returnUrl": "comwell://",
+ "reference": "flutter-test_${DateTime.now().millisecondsSinceEpoch}",
+ "channel": "iOS",
+ };
+ data.addAll(body);
+ data.remove("storePaymentMethod");
+ final response = await dio.post<Json>("https://checkout-test.adyen.com/v71/payments/details",
+ data: data,
+ options: Options(
+ headers: headers,
+ )) ;
+ return response.data!;
+ }
+
+ Future<String> createEndpointRegistration() async {
+ final response =
+ await dio.post<String>('/keys/v1/CreateEndpointRegistration');
+ final json = jsonDecode(response.data!) as Map<String, dynamic>;
+ return json["InvitationCode"]! as String;
+ }
+
+ Future<void> provisionKey(String bookingId) async {
+ await dio
+ .post<void>('/keys/v1/ProvisionKey', data: {'bookingId': bookingId});
+ }
}
diff --git a/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart b/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart
index 060b1c19..3e8e9ba0 100644
--- a/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart
+++ b/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart
@@ -40,14 +40,24 @@ class ResponseHandleInterceptor extends Interceptor {
}
@override
- void onError(
- DioException err, ErrorInterceptorHandler handler) async {
+ Future<dynamic> onError(
+ DioException err,
+ ErrorInterceptorHandler handler,
+ ) async {
final response = err.response;
- if (response == null) throw Exception("Missing response");
+ print("qqq err=$err");
+ if (response == null) {
+ return handler.next(DioException(
+ message: "Missing response",
+ requestOptions: RequestOptions(),
+ ));
+ }
final statusCode = response.statusCode;
try {
if (response.statusCode == 404) {
- throw DioException(requestOptions: response.requestOptions, error: 'Not found');
+ final err = DioException(
+ requestOptions: response.requestOptions, error: 'Not found');
+ handler.next(err);
} else if (statusCode == 401) {
final newToken = await _refreshToken();
if (newToken != null) {
@@ -65,15 +75,16 @@ class ResponseHandleInterceptor extends Interceptor {
return handler.resolve(retryRequest);
}
} else {
- throw DioException(
+ final err = DioException(
requestOptions: response.requestOptions,
error: 'HTTP request error, status code: ${response.statusCode}');
+ handler.next(err);
}
- } catch (e,stackTrace) {
- debugPrint('Error: $stackTrace');
- throw DioException(
+ } catch (e) {
+ final err = DioException(
requestOptions: response.requestOptions,
error: 'Failed to handle the response: $e');
+ handler.next(err);
}
}
diff --git a/comwell_key_app/lib/themes/comwell_colors.dart b/comwell_key_app/lib/themes/comwell_colors.dart
new file mode 100644
index 00000000..9b93b658
--- /dev/null
+++ b/comwell_key_app/lib/themes/comwell_colors.dart
@@ -0,0 +1,44 @@
+
+
+import 'package:flutter/material.dart';
+
+const colorPrimary = Color(0xFF677169);
+const colorSecondary = Color(0xffF0EAE2);
+const colorBackground = Color(0xFFE8E8E8);
+const colorPrimaryText = Color(0xFF000000);
+const colorSecondaryText = Color(0xFF000000);
+const colorOnPrimaryTextColor = Color(0xFFFFFFFF);
+const colorPrimarySystem = Color(0xFF000000);
+const colorSecondarySystem = Color.fromARGB(237, 227, 216, 1);
+const colorTertiary = Color(0xFF000000);
+const colorTertiaryText = Color(0xFF000000);
+const colorTertiarySystem = Color(0xFF000000);
+const colorShadow = Color(0xFF000000);
+const colorDivider = Color(0xFFE0E0E0);
+const disabledButtonColor = Color(0xFFF0F0F0);
+const colorError = Color(0xFFEB0026);
+
+const colorBlack = MaterialColor(0xFF000000, {
+ 75: Color(0xB3000000),
+ 65: Color(0xA6000000),
+});
+
+const int _earthColor = 0xFF677169;
+const earthColor = MaterialColor(_earthColor, <int, Color>{
+ 100: Color(_earthColor),
+ 80: Color.fromRGBO(128, 139, 130, 1.0),
+ 60: Color.fromRGBO(160, 171, 163, 1.0),
+ 40: Color.fromRGBO(192, 200, 194, 1.0),
+ 20: Color.fromRGBO(227, 230, 227, 1.0),
+ 10: Color.fromRGBO(238, 239, 238, 1.0),
+});
+
+const int _sandColor = 0xFFAA8D65;
+const sandColor = MaterialColor(_sandColor, <int, Color>{
+ 100: Color(_sandColor),
+ 80: Color.fromRGBO(190, 161, 121, 1.0),
+ 60: Color.fromRGBO(215, 201, 185, 1.0),
+ 40: Color.fromRGBO(237, 227, 216, 1.0),
+ 20: Color.fromRGBO(240, 234, 226, 1.0),
+ 10: Color.fromRGBO(249, 246, 242, 1.0),
+});
\ No newline at end of file