6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit 858ca06e

AuthorEdmir Suljic<esu@dwarf.dk>
Date2025-08-22 11:58:08 +0200
Finished new payment feature. Also redid the housekeeping implementation a bit in this branch

Changed files

comwell_key_app/assets/translations/da-DK.json     |   3 +-
 comwell_key_app/assets/translations/en-US.json     |   3 +-
 .../booking_details/bloc/booking_details_bloc.dart |  24 +++-
 .../bloc/booking_details_event.dart                |   9 ++
 .../lib/booking_details/booking_details_page.dart  |  21 ++-
 .../booking_details_repository.dart                |  21 +--
 .../components/check_in_button_timer.dart          |   1 +
 .../components/housekeeping_button.dart            |  19 ++-
 .../components/preregister_button.dart             |  15 ++
 .../lib/check_in/bloc/check_in_cubit.dart          |   4 +-
 .../lib/check_out/bloc/check_out_cubit.dart        |  30 +---
 .../lib/check_out/bloc/check_out_state.dart        |  28 ++--
 comwell_key_app/lib/check_out/check_out_flow.dart  |  64 +++++----
 .../components/check_out_bottom_sheet.dart         |   1 -
 .../components/checkout_itemized_bill.dart         |   6 +-
 .../lib/check_out/pages/check_out_error_page.dart  |   1 -
 .../check_out/pages/check_out_processing_page.dart |  92 +++++-------
 .../check_out/pages/check_out_success_page.dart    |   4 -
 .../lib/housekeeping/cubit/housekeeping_cubit.dart |   7 +-
 .../lib/housekeeping/housekeeping_page.dart        |   7 +-
 .../lib/housekeeping/housekeeping_repository.dart  |  23 ++-
 .../lib/my_booking/cubit/my_booking_cubit.dart     |  30 +++-
 .../lib/my_booking/cubit/my_booking_state.dart     |   5 +-
 .../lib/my_booking/my_booking_page.dart            | 156 ++++++++++++---------
 .../my_booking/pages/my_booking_payment_page.dart  |   3 +-
 .../lib/payment/cubit/payment_cubit.dart           |   2 +
 .../lib/payment/payment_processing_page.dart       |   5 -
 .../pregistration/cubit/preregistration_cubit.dart |  24 ++--
 .../pregistration/cubit/preregistration_state.dart |  11 +-
 comwell_key_app/lib/routing/app_router.dart        |  57 ++++----
 comwell_key_app/lib/utils/locator.dart             |   4 +
 .../booking_details_bloc_test.dart                 |   8 ++
 32 files changed, 384 insertions(+), 304 deletions(-)

Diff

diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index c25700f4..9230da0d 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -329,5 +329,6 @@
"remove": "Fjern",
"up_sales_processing_error_title": "Kunne ikke tilføje tilkøb",
"pay_bill": "Betal regning",
- "discount": "Comwell Club Point Rabat"
+ "discount": "Comwell Club Point Rabat",
+ "error_preregistration": "Kunne ikke preregister, gå til reception"
}
\ 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 96de89d1..2f74b31f 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -332,5 +332,6 @@
"remove": "Remove",
"up_sales_processing_error_title": "Failed to add addons",
"pay_bill": "Pay bill",
- "discount": "Comwell Club Points Discount"
+ "discount": "Comwell Club Points Discount",
+ "error_preregistration": "Failed to preregister, go to reception"
}
diff --git a/comwell_key_app/lib/booking_details/bloc/booking_details_bloc.dart b/comwell_key_app/lib/booking_details/bloc/booking_details_bloc.dart
index 4d2c9160..04b5bea6 100644
--- a/comwell_key_app/lib/booking_details/bloc/booking_details_bloc.dart
+++ b/comwell_key_app/lib/booking_details/bloc/booking_details_bloc.dart
@@ -1,5 +1,8 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
+import 'package:comwell_key_app/housekeeping/components/housekeeping_service.dart';
+import 'package:comwell_key_app/housekeeping/housekeeping_repository.dart';
+import 'package:comwell_key_app/housekeeping/models/housekeeping.dart';
import 'package:comwell_key_app/overview/models/guest.dart';
import 'package:comwell_key_app/profile/profile_repository.dart';
import 'package:comwell_key_app/profile_settings/model/user.dart';
@@ -29,12 +32,14 @@ class BookingDetailsBloc
final SeosRepository seosRepository = locator<SeosRepository>();
Duration _remainingTime = Duration.zero;
final UpSalesRepository upSaleRepository;
+ final HouseKeepingRepository houseKeepingRepository;
BookingDetailsBloc(
this.booking, {
required this.bookingDetailsRepository,
required this.profileRepository,
required this.upSaleRepository,
+ required this.houseKeepingRepository,
}) : super(BookingDetailsState.initial(booking)) {
on<InitialEvent>((event, emit) async {
try {
@@ -61,13 +66,16 @@ class BookingDetailsBloc
try {
await getUpSales(emit);
emit(state.main());
-
} catch (e) {
if (kDebugMode) print("err=$e");
emit(state.setupError());
}
});
+ on<OrderHouseKeepingEvent>((event, emit) async {
+ await orderHouseKeeping(emit, event.selectedServices);
+ });
+
on<UpdateRemainingEvent>((event, emit) async {
await updateRemainingTime(emit);
});
@@ -130,7 +138,7 @@ class BookingDetailsBloc
Future<void> checkIfHouseKeepingOrdered(
Emitter<BookingDetailsState> emit) async {
- final isHouseKeepingOrdered = await bookingDetailsRepository
+ final isHouseKeepingOrdered = await houseKeepingRepository
.isHousesKeepingOrdered(booking.roomNumber);
if (isHouseKeepingOrdered) {
@@ -138,6 +146,18 @@ class BookingDetailsBloc
}
}
+ Future<void> orderHouseKeeping(Emitter<BookingDetailsState> emit, List<String> selectedServices) async {
+ final housekeeping = Housekeeping.toJson(
+ booking.hotelCode,
+ booking.roomNumber,
+ selectedServices
+ .map((e) => HouseKeepingService.values
+ .firstWhere((element) => element.name == e))
+ .toList());
+ await houseKeepingRepository.saveHouseKeepingOrdered(housekeeping);
+ emit(state.houseKeepingOrdered());
+ }
+
Future<void> updateBooking(Emitter<BookingDetailsState> emit, Booking booking,
UpdateBookingEvent event) async {
try {
diff --git a/comwell_key_app/lib/booking_details/bloc/booking_details_event.dart b/comwell_key_app/lib/booking_details/bloc/booking_details_event.dart
index 8230291d..684a7b73 100644
--- a/comwell_key_app/lib/booking_details/bloc/booking_details_event.dart
+++ b/comwell_key_app/lib/booking_details/bloc/booking_details_event.dart
@@ -55,3 +55,12 @@ final class UpdateBookingEvent extends BookingDetailsEvent {
@override
List<Object> get props => [booking];
}
+
+final class OrderHouseKeepingEvent extends BookingDetailsEvent {
+ final List<String> selectedServices;
+
+ const OrderHouseKeepingEvent(this.selectedServices);
+
+ @override
+ List<Object> get props => [selectedServices];
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/booking_details/booking_details_page.dart b/comwell_key_app/lib/booking_details/booking_details_page.dart
index 7934b24d..b7ee3266 100644
--- a/comwell_key_app/lib/booking_details/booking_details_page.dart
+++ b/comwell_key_app/lib/booking_details/booking_details_page.dart
@@ -31,7 +31,7 @@ class BookingDetailsPage extends StatelessWidget {
cubit.add(InitialEvent());
}
- print("qqq booking ${cubit.booking}");
+ debugPrint("booking ${cubit.booking}");
return Scaffold(
extendBodyBehindAppBar: true,
@@ -121,8 +121,9 @@ class BookingDetailsPage extends StatelessWidget {
Widget _buildBookingDetailsInformation(BuildContext context,
BookingDetailsState state, BookingDetailsBloc cubit, ThemeData theme) {
return InkWell(
- onTap: () {
- context.pushNamed(AppRoutes.myBooking.name, extra: cubit.booking);
+ onTap: () async {
+ await context.pushNamed(AppRoutes.myBooking.name, extra: cubit.booking);
+ cubit.add(InitialEvent());
},
child: Container(
width: double.infinity,
@@ -148,9 +149,8 @@ class BookingDetailsPage extends StatelessWidget {
children: [
Text(
cubit.booking.id,
- style: theme.textTheme.labelLarge?.copyWith(
- color: colorBackground
- ),
+ style: theme.textTheme.labelLarge
+ ?.copyWith(color: colorBackground),
),
Text(
cubit.booking.toRoomType(),
@@ -166,13 +166,12 @@ class BookingDetailsPage extends StatelessWidget {
Text(
'balance'.tr(),
textAlign: TextAlign.end,
- style: theme.textTheme.labelLarge?.copyWith(
- color: colorBackground
- ),
+ style: theme.textTheme.labelLarge
+ ?.copyWith(color: colorBackground),
),
Text(
- 'total_charge_value'.tr(
- args: [cubit.trimmedBalance]),
+ 'total_charge_value'
+ .tr(args: [cubit.trimmedBalance]),
style: theme.textTheme.headlineMedium?.copyWith(
color: colorBackground,
),
diff --git a/comwell_key_app/lib/booking_details/booking_details_repository.dart b/comwell_key_app/lib/booking_details/booking_details_repository.dart
index e6397b3c..e6fceb55 100644
--- a/comwell_key_app/lib/booking_details/booking_details_repository.dart
+++ b/comwell_key_app/lib/booking_details/booking_details_repository.dart
@@ -1,5 +1,4 @@
import 'package:comwell_key_app/database/comwell_db.dart';
-import 'package:comwell_key_app/housekeeping/housekeeping_repository.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/services/api.dart';
import 'package:comwell_key_app/services/mappers/booking_mapper.dart';
@@ -8,27 +7,9 @@ import 'package:comwell_key_app/utils/secure_storage.dart';
class BookingDetailsRepository {
final api = Api();
- final secureStorage = SecureStorage();
+ final secureStorage = locator<SecureStorage>();
- Future<bool> isHousesKeepingOrdered(String roomNumber) async {
- final lastOrderedValue = await secureStorage
- .read(HouseKeepingRepository.houseKeepingLastOrderedKey(roomNumber));
- if (lastOrderedValue != null) {
- final lastOrdered =
- DateTime.fromMillisecondsSinceEpoch(int.parse(lastOrderedValue))
- .copyWith(hour: 0, minute: 0, second: 0);
- final isToday = DateTime.now().copyWith(hour: 0, minute: 0, second: 0);
- final isNextDay = DateTime.now().isAfter(isToday) &&
- DateTime.now().isAfter(lastOrdered);
- final timeOfToday = DateTime.now().hour;
- final isHouseKeepingAllowed = isNextDay &&
- timeOfToday > 2; // If it's after 3am on the day after the order
-
- return isHouseKeepingAllowed;
- }
- return false;
- }
Future<String?> doesInvitationCodeExist(String key) async {
diff --git a/comwell_key_app/lib/booking_details/components/check_in_button_timer.dart b/comwell_key_app/lib/booking_details/components/check_in_button_timer.dart
index 27126f92..c6d9eda3 100644
--- a/comwell_key_app/lib/booking_details/components/check_in_button_timer.dart
+++ b/comwell_key_app/lib/booking_details/components/check_in_button_timer.dart
@@ -20,6 +20,7 @@ class _CheckInButtonTimerState extends State<CheckInButtonTimer> {
Widget build(BuildContext context) {
return BlocBuilder<BookingDetailsBloc, BookingDetailsState>(
builder: (context, state) {
+
return AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
transitionBuilder: (Widget child, Animation<double> animation) {
diff --git a/comwell_key_app/lib/booking_details/components/housekeeping_button.dart b/comwell_key_app/lib/booking_details/components/housekeeping_button.dart
index 6774207a..899592ee 100644
--- a/comwell_key_app/lib/booking_details/components/housekeeping_button.dart
+++ b/comwell_key_app/lib/booking_details/components/housekeeping_button.dart
@@ -29,7 +29,12 @@ class HousekeepingButton extends StatelessWidget {
borderRadius: BorderRadius.circular(10),
onTap: () async {
if (bloc.state.isHouseKeepingOrdered) return;
- await context.pushNamed(AppRoutes.houseKeeping.name, extra: booking);
+
+ final result = await context.pushNamed(AppRoutes.houseKeeping.name,
+ extra: booking);
+ if (result != null && !bloc.isClosed) {
+ bloc.add(OrderHouseKeepingEvent(result as List<String>));
+ }
if(!bloc.isClosed) bloc.add(CheckIfHouseKeepingOrdered());
},
child: Padding(
@@ -55,12 +60,20 @@ class HousekeepingButton extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
- bloc.state.isHouseKeepingOrdered == true ? "booking_details_page_housekeeping_button_title_ordered".tr() : "booking_details_page_housekeeping_button_title".tr(),
+ bloc.state.isHouseKeepingOrdered == true
+ ? "booking_details_page_housekeeping_button_title_ordered"
+ .tr()
+ : "booking_details_page_housekeeping_button_title"
+ .tr(),
style: Theme.of(context).textTheme.headlineSmall,
maxLines: 1,
),
Text(
- bloc.state.isHouseKeepingOrdered == true ? "booking_details_page_housekeeping_button_subtitle_ordered".tr() : "booking_details_page_housekeeping_button_subtitle".tr(),
+ bloc.state.isHouseKeepingOrdered == true
+ ? "booking_details_page_housekeeping_button_subtitle_ordered"
+ .tr()
+ : "booking_details_page_housekeeping_button_subtitle"
+ .tr(),
maxLines: 1,
softWrap: true,
style: Theme.of(context)
diff --git a/comwell_key_app/lib/booking_details/components/preregister_button.dart b/comwell_key_app/lib/booking_details/components/preregister_button.dart
index 1e8cf3fe..b02f37fb 100644
--- a/comwell_key_app/lib/booking_details/components/preregister_button.dart
+++ b/comwell_key_app/lib/booking_details/components/preregister_button.dart
@@ -24,6 +24,21 @@ class PreregisterButton extends StatelessWidget {
extra: [bloc.booking, bloc.state.upSales]);
if (result != null) {
bloc.add(InitialEvent());
+ } else {
+ if (!context.mounted) return;
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(
+ content: Text(
+ "error_preregistration".tr(),
+ style: theme.textTheme.bodyMedium,
+ textAlign: TextAlign.center,
+ ),
+ backgroundColor: theme.scaffoldBackgroundColor,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(12),
+ ),
+ ),
+ );
}
},
child: Padding(
diff --git a/comwell_key_app/lib/check_in/bloc/check_in_cubit.dart b/comwell_key_app/lib/check_in/bloc/check_in_cubit.dart
index fcfff3e3..9ac3c840 100644
--- a/comwell_key_app/lib/check_in/bloc/check_in_cubit.dart
+++ b/comwell_key_app/lib/check_in/bloc/check_in_cubit.dart
@@ -20,8 +20,8 @@ class CheckInCubit extends Cubit<CheckInState> {
await _checkInRepository.checkIn(booking.confirmationId);
final bookingDetails = await _checkInRepository.getBookingDetails(booking.id);
emit(state.checkInStatusRoomFound(roomNumber: bookingDetails.roomNumber));
- await _checkInRepository.checkIfSetup();
- await tryGetKeys();
+ //await _checkInRepository.checkIfSetup();
+ // await tryGetKeys();
await Future<void>.delayed(const Duration(milliseconds: 1000));
emit(state.checkInStatusYourDigitalCard(
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 4eb142ba..6dd36e0f 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
@@ -2,9 +2,7 @@ import 'package:adyen_checkout/adyen_checkout.dart';
import 'package:bloc/bloc.dart';
import 'package:comwell_key_app/check_out/bloc/check_out_state.dart';
import 'package:comwell_key_app/check_out/check_out_repository.dart';
-import 'package:comwell_key_app/payment/cubit/payment_processing_state.dart';
import 'package:comwell_key_app/check_out/pages/check_out_page.dart';
-import 'package:comwell_key_app/check_out/utils/constants.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/pregistration/pregistration_repository.dart';
import 'package:comwell_key_app/profile/profile_repository.dart';
@@ -39,6 +37,7 @@ class CheckoutCubit extends Cubit<CheckoutState> {
void init() async {
try {
+ //TODO: Fetch club points eventually
final user = await profileRepository.fetchProfileSettings();
//emit(state.clubPointsFetched(user.points));
setItems(booking.addOnItems ?? []);
@@ -83,7 +82,7 @@ class CheckoutCubit extends Cubit<CheckoutState> {
Future<void> processCheckoutWithoutPaying() async {
try {
- await checkOutRepository.checkOut(booking.confirmationId);
+ checkOut();
} catch (e) {
await Future<void>.delayed(const Duration(milliseconds: 1000));
}
@@ -95,6 +94,7 @@ class CheckoutCubit extends Cubit<CheckoutState> {
switch (currentPage) {
case CheckoutPage.confirmation:
if (booking.balance == 0) {
+ emit(state.paymentProcessingNotNeeded());
return _navigateToProcessing(context);
}
return _navigateTo(CheckoutPage.payment);
@@ -161,8 +161,8 @@ class CheckoutCubit extends Cubit<CheckoutState> {
if (booking.balance == 0) {
await checkOutRepository.checkOut(booking.confirmationId);
- emit(state.checkoutSuccess());
+ emit(state.checkoutSuccess());
} else {
emit(state.checkoutError());
}
@@ -172,28 +172,6 @@ class CheckoutCubit extends Cubit<CheckoutState> {
}
}
- Future<void> createSession() async {
- try {
- final bookingPrice = state.totalPriceAfterDiscount;
- final amount = Amount(
- value: booking.balance?.toInt() ?? 0,
- currency: currency,
- );
-
- final paymentConfigurations =
- await preregistrationRepository.sessionCheckout(
- amount, booking.confirmationId, state.applyClubPoints);
- if (paymentConfigurations == null) {
- checkOut();
- } else {
- await Future<void>.delayed(const Duration(milliseconds: 4000));
- emit(state.checkoutSuccess());
- }
- } catch (e) {
- await Future<void>.delayed(const Duration(milliseconds: 1000));
- }
- }
-
Future<void> onPaymentResult(PaymentResult result) async {
switch (result) {
case PaymentAdvancedFinished():
diff --git a/comwell_key_app/lib/check_out/bloc/check_out_state.dart b/comwell_key_app/lib/check_out/bloc/check_out_state.dart
index 3fe7111b..8fb5f812 100644
--- a/comwell_key_app/lib/check_out/bloc/check_out_state.dart
+++ b/comwell_key_app/lib/check_out/bloc/check_out_state.dart
@@ -1,5 +1,4 @@
-import 'package:comwell_key_app/payment/cubit/payment_processing_state.dart';
import 'package:comwell_key_app/check_out/models/payment_method.dart';
import 'package:comwell_key_app/services/models/booking_dto.dart';
import 'package:comwell_key_app/check_out/pages/check_out_page.dart';
@@ -10,14 +9,13 @@ class CheckoutState extends Equatable {
final Iterable<BookingAddonItem> _items;
final bool isTermsAccepted;
final bool applyClubPoints;
- final int clubPoints;
- final PaymentProcessingState processingState;
+ final int clubPoints;
final bool successfulCheckout;
final CheckoutPage page;
final CheckoutPaymentMethod? paymentMethod;
final bool showTermsError;
final num bookingBalance;
-
+ final bool isPaymentProcessingNeeded;
int get totalPriceBeforeDiscount => _sumOfList(_items);
@@ -48,23 +46,22 @@ class CheckoutState extends Equatable {
required this.showTermsError,
required this.clubPoints,
required this.applyClubPoints,
- required this.processingState,
this.paymentMethod,
required this.bookingBalance,
required this.successfulCheckout,
+ required this.isPaymentProcessingNeeded,
}) : _items = items;
- CheckoutState.initial(num bookingBalance)
+ CheckoutState.initial(this.bookingBalance)
: _items = [],
isTermsAccepted = false,
page = CheckoutPage.confirmation,
showTermsError = false,
clubPoints = 500,
paymentMethod = CheckoutPaymentMethod.creditCard,
- processingState = PaymentProcessingStateNotStarted(),
applyClubPoints = false,
- bookingBalance = bookingBalance,
- successfulCheckout = false;
+ successfulCheckout = false,
+ isPaymentProcessingNeeded = true;
CheckoutState itemsUpdated(Iterable<BookingAddonItem> items) {
@@ -97,30 +94,34 @@ class CheckoutState extends Equatable {
CheckoutState checkoutError() => _copyWith(successfulCheckout: false);
+ CheckoutState paymentProcessingNeeded() => _copyWith(isPaymentProcessingNeeded: true);
+
+ CheckoutState paymentProcessingNotNeeded() => _copyWith(isPaymentProcessingNeeded: false);
+
CheckoutState _copyWith({
Iterable<BookingAddonItem>? items,
bool? termsAccepted,
bool? applyClubPoints,
- PaymentProcessingState? updateProcessingState,
CheckoutPage? page,
CheckoutPaymentMethod? paymentMethod,
int? clubPoints,
bool? showTermsError,
num? bookingBalance,
bool? successfulCheckout,
+ bool? isPaymentProcessingNeeded,
}) {
return CheckoutState(
items: items ?? _items,
page: page ?? this.page,
clubPoints: clubPoints ?? this.clubPoints,
showTermsError: showTermsError ?? this.showTermsError,
- processingState: updateProcessingState ?? processingState,
isTermsAccepted: termsAccepted ?? isTermsAccepted,
applyClubPoints: applyClubPoints ?? this.applyClubPoints,
paymentMethod: paymentMethod ?? this.paymentMethod,
bookingBalance: bookingBalance ?? this.bookingBalance,
- successfulCheckout: successfulCheckout ?? this.successfulCheckout);
+ successfulCheckout: successfulCheckout ?? this.successfulCheckout,
+ isPaymentProcessingNeeded: isPaymentProcessingNeeded ?? this.isPaymentProcessingNeeded);
}
@override
@@ -129,7 +130,6 @@ class CheckoutState extends Equatable {
_items,
isTermsAccepted,
applyClubPoints,
- processingState,
page,
showTermsError,
paymentMethod,
@@ -137,5 +137,7 @@ class CheckoutState extends Equatable {
totalPriceAfterDiscount,
totalPrice,
successfulCheckout,
+ isPaymentProcessingNeeded,
];
}
+
diff --git a/comwell_key_app/lib/check_out/check_out_flow.dart b/comwell_key_app/lib/check_out/check_out_flow.dart
index b2c01640..93f1814d 100644
--- a/comwell_key_app/lib/check_out/check_out_flow.dart
+++ b/comwell_key_app/lib/check_out/check_out_flow.dart
@@ -1,5 +1,6 @@
import 'package:comwell_key_app/check_out/bloc/check_out_cubit.dart';
import 'package:comwell_key_app/check_out/components/check_out_bottom_sheet.dart';
+import 'package:comwell_key_app/check_out/pages/check_out_processing_page.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_page.dart';
@@ -15,36 +16,41 @@ class CheckOutFlow extends StatelessWidget {
@override
Widget build(BuildContext context) {
final cubit = context.read<CheckoutCubit>();
- return BlocListener<PaymentCubit, PaymentProcessingState>(
- listener: (context, state) async {
- if (state is PaymentProcessingStateConfirmed) {
- //This is here to add time so that the payment is represented in the BookingDetails
- await Future<void>.delayed(const Duration(seconds: 5));
- await cubit.checkOut();
- if (cubit.state.successfulCheckout && context.mounted) {
- context.pushNamed(AppRoutes.checkOutSuccess.name, extra: cubit.booking.digitalCard);
- } else if (context.mounted) {
- context.pushNamed(AppRoutes.checkOutError.name);
+ if (!cubit.state.isPaymentProcessingNeeded) {
+ return const CheckOutProcessingPage();
+ } else {
+ return BlocListener<PaymentCubit, PaymentProcessingState>(
+ listener: (context, state) async {
+ if (state is PaymentProcessingStateConfirmed) {
+ //This is here to add time so that the payment is represented in the BookingDetails
+ await Future<void>.delayed(const Duration(seconds: 5));
+ await cubit.checkOut();
+ if (cubit.state.successfulCheckout && context.mounted) {
+ context.pushNamed(AppRoutes.checkOutSuccess.name,
+ extra: cubit.booking.digitalCard);
+ } else if (context.mounted) {
+ context.pushNamed(AppRoutes.checkOutError.name);
+ }
}
- }
- },
- child: Scaffold(
- appBar: ComwellAppBar(
- shouldShowProfileButton: false,
- onBackPressed: () {
- final didScroll = cubit.onBackPressed();
- if (!didScroll) context.pop();
- },
+ },
+ child: Scaffold(
+ appBar: ComwellAppBar(
+ shouldShowProfileButton: false,
+ onBackPressed: () {
+ final didScroll = cubit.onBackPressed();
+ if (!didScroll) context.pop();
+ },
+ ),
+ bottomSheet: const CheckOutBottomSheet(),
+ backgroundColor: Colors.white,
+ body: PageView(
+ controller: cubit.pageController,
+ key: const PageStorageKey("check_out_flow"),
+ physics: const NeverScrollableScrollPhysics(),
+ children: CheckoutPage.getPages(ValueKey(cubit.state)).toList(),
+ ),
),
- bottomSheet: const CheckOutBottomSheet(),
- backgroundColor: Colors.white,
- body: PageView(
- controller: cubit.pageController,
- key: const PageStorageKey("check_out_flow"),
- physics: const NeverScrollableScrollPhysics(),
- children: CheckoutPage.getPages(ValueKey(cubit.state)).toList(),
- ),
- ),
- );
+ );
+ }
}
}
diff --git a/comwell_key_app/lib/check_out/components/check_out_bottom_sheet.dart b/comwell_key_app/lib/check_out/components/check_out_bottom_sheet.dart
index c0288d2a..da117cad 100644
--- a/comwell_key_app/lib/check_out/components/check_out_bottom_sheet.dart
+++ b/comwell_key_app/lib/check_out/components/check_out_bottom_sheet.dart
@@ -2,7 +2,6 @@ import 'dart:io';
import 'package:comwell_key_app/check_out/bloc/check_out_cubit.dart';
import 'package:comwell_key_app/check_out/models/payment_method.dart';
-import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
diff --git a/comwell_key_app/lib/check_out/components/checkout_itemized_bill.dart b/comwell_key_app/lib/check_out/components/checkout_itemized_bill.dart
index 4bef3ee4..018318b3 100644
--- a/comwell_key_app/lib/check_out/components/checkout_itemized_bill.dart
+++ b/comwell_key_app/lib/check_out/components/checkout_itemized_bill.dart
@@ -1,10 +1,8 @@
-import 'package:comwell_key_app/check_out/bloc/check_out_cubit.dart';
import 'package:comwell_key_app/check_out/components/check_out_bill_list_item.dart';
import 'package:comwell_key_app/services/models/booking_dto.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';
class CheckoutItemizedBill extends StatelessWidget {
final Iterable<BookingAddonItem> addOnItems;
@@ -35,14 +33,14 @@ class CheckoutItemizedBill extends StatelessWidget {
Row(
children: [
Text(
- "${totalPriceBeforeDiscount}",
+ "$totalPriceBeforeDiscount",
style: const TextStyle(
decoration: TextDecoration.lineThrough,
decorationColor: colorDivider,
color: colorDivider),
),
const SizedBox(width: 4),
- Text("${totalPriceAfterDiscount}"),
+ Text("$totalPriceAfterDiscount"),
],
)
else
diff --git a/comwell_key_app/lib/check_out/pages/check_out_error_page.dart b/comwell_key_app/lib/check_out/pages/check_out_error_page.dart
index 433cc49c..8a84eef3 100644
--- a/comwell_key_app/lib/check_out/pages/check_out_error_page.dart
+++ b/comwell_key_app/lib/check_out/pages/check_out_error_page.dart
@@ -2,7 +2,6 @@ import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
-import 'package:go_router/go_router.dart';
class CheckOutErrorPage extends StatelessWidget {
const CheckOutErrorPage({super.key});
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 dc48cabe..f1d2537c 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
@@ -1,12 +1,11 @@
-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_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/check_out/bloc/check_out_state.dart';
+import 'package:comwell_key_app/routing/app_routes.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:go_router/go_router.dart';
import 'package:lottie/lottie.dart';
class CheckOutProcessingPage extends StatefulWidget {
@@ -66,66 +65,39 @@ class _CheckOutProcessingPageState extends State<CheckOutProcessingPage>
if (mounted) Navigator.of(context).pop();
}
- void showAdyenModal(BuildContext context) async {
- final cubit = context.read<CheckoutCubit>();
- final processingState = cubit.state.processingState;
- 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 {
- }
- }
-
@override
Widget build(BuildContext context) {
final cubit = context.read<CheckoutCubit>();
- return Scaffold(
- body: Container(
- alignment: Alignment.center,
- color: sandColor[80],
- child: Builder(builder: (context) {
- final processingState = cubit.state.processingState;
- if (processingState is PaymentProcessingStateConfirmed) {
- return CheckOutSuccessPage(digitalCard: cubit.booking.digitalCard);
- } else if (processingState is PaymentProcessingStateError) {
- return const CheckOutErrorPage();
- } else 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.processingState) {
- case PaymentProcessingStateConfirmed _:
- playSuccess();
- case PaymentProcessingStateError _:
- playError();
- default:
- playLoading();
+ return BlocListener<CheckoutCubit, CheckoutState>(
+ listener: (context, state) {
+ if (state.successfulCheckout) {
+ context.pushNamed(AppRoutes.checkOutSuccess.name,
+ extra: cubit.booking.digitalCard);
+ } else {
+ context.pushNamed(AppRoutes.checkOutError.name);
+ }
+ },
+ child: Scaffold(
+ body: Container(
+ alignment: Alignment.center,
+ color: sandColor[80],
+ child: Builder(builder: (context) {
+ return Lottie.asset(
+ 'assets/animations/load_animation.json',
+ controller: animationController,
+ onLoaded: (composition) {
+ if (loadingComposition == null) {
+ loadingComposition = composition;
+ animationController.duration = composition.duration;
+ playLoading();
}
- }
- },
- fit: BoxFit.cover,
- width: 64,
- height: 64,
- );
- }),
+ },
+ fit: BoxFit.cover,
+ width: 64,
+ height: 64,
+ );
+ }),
+ ),
),
);
}
diff --git a/comwell_key_app/lib/check_out/pages/check_out_success_page.dart b/comwell_key_app/lib/check_out/pages/check_out_success_page.dart
index 20cebcd5..9dafe22f 100644
--- a/comwell_key_app/lib/check_out/pages/check_out_success_page.dart
+++ b/comwell_key_app/lib/check_out/pages/check_out_success_page.dart
@@ -1,12 +1,8 @@
-import 'package:comwell_key_app/check_out/bloc/check_out_cubit.dart';
import 'package:comwell_key_app/check_out/components/check_out_countdown.dart';
-import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/routing/app_routes.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:go_router/go_router.dart';
class CheckOutSuccessPage extends StatelessWidget {
final bool digitalCard;
diff --git a/comwell_key_app/lib/housekeeping/cubit/housekeeping_cubit.dart b/comwell_key_app/lib/housekeeping/cubit/housekeeping_cubit.dart
index 86e7ab9a..b70b51a5 100644
--- a/comwell_key_app/lib/housekeeping/cubit/housekeeping_cubit.dart
+++ b/comwell_key_app/lib/housekeeping/cubit/housekeeping_cubit.dart
@@ -1,6 +1,5 @@
import 'package:bloc/bloc.dart';
import 'package:comwell_key_app/housekeeping/cubit/housekeeping_state.dart';
-import 'package:comwell_key_app/housekeeping/models/housekeeping.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/tracking/comwell_tracking.dart';
import 'package:comwell_key_app/tracking/models/analytics_event_item.dart';
@@ -41,9 +40,8 @@ class HouseKeepingCubit extends Cubit<HouseKeepingState> {
}
}
- Future<void> onOrderHousekeepingClicked(Booking booking) async {
- final housekeeping = Housekeeping.toJson(booking.hotelCode, booking.roomNumber, state.selectedServices.map((e) => HouseKeepingService.values.firstWhere((element) => element.name == e)).toList());
- await houseKeepingRepository.saveHouseKeepingOrdered(housekeeping);
+ Future<List<String>> onOrderHousekeepingClicked(Booking booking) async {
+
final analyticsEventItem = AnalyticsEventItem(
hotelName: "Comwell",
currency: "DKK",
@@ -55,5 +53,6 @@ class HouseKeepingCubit extends Cubit<HouseKeepingState> {
price: 0,
quantity: 1);
tracking.trackAddToCart(analyticsEventItem);
+ return state.selectedServices.toList();
}
}
\ No newline at end of file
diff --git a/comwell_key_app/lib/housekeeping/housekeeping_page.dart b/comwell_key_app/lib/housekeeping/housekeeping_page.dart
index bec88d04..2f27081e 100644
--- a/comwell_key_app/lib/housekeeping/housekeeping_page.dart
+++ b/comwell_key_app/lib/housekeeping/housekeeping_page.dart
@@ -19,7 +19,6 @@ class HousekeepingPage extends StatefulWidget {
}
class _HousekeepingPageState extends State<HousekeepingPage> {
-
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
@@ -46,9 +45,11 @@ class _HousekeepingPageState extends State<HousekeepingPage> {
padding: const EdgeInsets.all(16.0),
child: ElevatedButton(
onPressed: () async {
- await cubit.onOrderHousekeepingClicked(widget.booking);
+ final selectedServices = await cubit
+ .onOrderHousekeepingClicked(widget.booking);
+
if (context.mounted) {
- context.pop();
+ context.pop(selectedServices);
}
},
style: const ButtonStyle(
diff --git a/comwell_key_app/lib/housekeeping/housekeeping_repository.dart b/comwell_key_app/lib/housekeeping/housekeeping_repository.dart
index 56a6dcb9..35394fba 100644
--- a/comwell_key_app/lib/housekeeping/housekeeping_repository.dart
+++ b/comwell_key_app/lib/housekeeping/housekeeping_repository.dart
@@ -1,10 +1,11 @@
import 'package:comwell_key_app/housekeeping/models/housekeeping.dart';
import 'package:comwell_key_app/services/api.dart';
+import 'package:comwell_key_app/utils/locator.dart';
import '../utils/secure_storage.dart';
class HouseKeepingRepository {
- final secureStorage = SecureStorage();
+ final secureStorage = locator<SecureStorage>();
final api = Api();
Future<void> saveHouseKeepingOrdered(Housekeeping housekeeping) async {
@@ -14,6 +15,26 @@ class HouseKeepingRepository {
await api.orderHousekeeping(housekeeping);
}
+ Future<bool> isHousesKeepingOrdered(String roomNumber) async {
+ final lastOrderedValue = await secureStorage
+ .read(HouseKeepingRepository.houseKeepingLastOrderedKey(roomNumber));
+ if (lastOrderedValue != null) {
+ final lastOrdered =
+ DateTime.fromMillisecondsSinceEpoch(int.parse(lastOrderedValue))
+ .copyWith(hour: 0, minute: 0, second: 0);
+
+ final isToday = DateTime.now().copyWith(hour: 0, minute: 0, second: 0);
+ final isNextDay = DateTime.now().isAfter(isToday) &&
+ DateTime.now().isAfter(lastOrdered);
+ final timeOfToday = DateTime.now().hour;
+ final isHouseKeepingAllowed = isNextDay &&
+ timeOfToday > 2; // If it's after 3am on the day after the order
+
+ return isHouseKeepingAllowed;
+ }
+ return false;
+ }
+
static String houseKeepingLastOrderedKey(String roomNumber) =>
'housekeeping_last_ordered_$roomNumber';
}
diff --git a/comwell_key_app/lib/my_booking/cubit/my_booking_cubit.dart b/comwell_key_app/lib/my_booking/cubit/my_booking_cubit.dart
index 48210a5a..d75177a8 100644
--- a/comwell_key_app/lib/my_booking/cubit/my_booking_cubit.dart
+++ b/comwell_key_app/lib/my_booking/cubit/my_booking_cubit.dart
@@ -1,9 +1,11 @@
-import 'package:adyen_checkout/adyen_checkout.dart';
import 'package:comwell_key_app/my_booking/cubit/my_booking_state.dart';
import 'package:comwell_key_app/my_booking/my_booking_repository.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
+import 'package:comwell_key_app/payment/cubit/payment_cubit.dart';
import 'package:comwell_key_app/profile/profile_repository.dart';
import 'package:comwell_key_app/profile/utils/urls.dart';
+import 'package:comwell_key_app/tracking/comwell_tracking.dart';
+import 'package:comwell_key_app/tracking/models/analytics_event_item.dart';
import 'package:comwell_key_app/utils/locator.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -12,8 +14,11 @@ class MyBookingCubit extends Cubit<MyBookingState> {
final MyBookingRepository myBookingRepository;
final ProfileRepository profileRepository = locator<ProfileRepository>();
late Booking booking;
+ final _tracking = locator<ComwellTracking>();
+ final PaymentCubit paymentServicesCubit;
- MyBookingCubit(this.myBookingRepository, {required Booking initialBooking})
+ MyBookingCubit(this.myBookingRepository, this.paymentServicesCubit,
+ {required Booking initialBooking})
: super(MyBookingState(
booking: initialBooking,
isLoading: false,
@@ -63,4 +68,25 @@ class MyBookingCubit extends Cubit<MyBookingState> {
launchUrl(Uri.parse(ComwellUrls.termsAndConditions));
}
+ Future<void> processPayment() async {
+ //TODO: Finish this when upsales are implemented
+ final analyticsEventItem = AnalyticsEventItem(
+ hotelName: booking.hotelName,
+ currency: "DKK",
+ value: booking.balance?.toInt() ?? 0,
+ placement: "placement",
+ items: booking.addOnItems?.map((e) => e.description).toList() ?? [],
+ itemId: "itemId",
+ itemName: "itemName",
+ price: booking.balance?.toInt() ?? 0,
+ quantity: 1);
+ _tracking.trackBeginCheckout(analyticsEventItem);
+ try {
+ await paymentServicesCubit.createSession(booking.balance?.toInt() ?? 0,
+ booking.confirmationId, state.applyClubPoints);
+ await Future<void>.delayed(const Duration(milliseconds: 4000));
+ } catch (e) {
+ emit(state.setError());
+ }
+ }
}
diff --git a/comwell_key_app/lib/my_booking/cubit/my_booking_state.dart b/comwell_key_app/lib/my_booking/cubit/my_booking_state.dart
index dc85e800..8907d56e 100644
--- a/comwell_key_app/lib/my_booking/cubit/my_booking_state.dart
+++ b/comwell_key_app/lib/my_booking/cubit/my_booking_state.dart
@@ -49,14 +49,13 @@ class MyBookingState extends Equatable {
.reduce((total, price) => total + price);
}
- MyBookingState.initial(Booking booking)
+ MyBookingState.initial(Booking this.booking)
: isTermsAccepted = false,
error = null,
isLoading = false,
showTermsError = false,
clubPoints = 0,
applyClubPoints = false,
- booking = booking,
_items = [];
MyBookingState termsAccepted() =>
@@ -73,6 +72,8 @@ class MyBookingState extends Equatable {
MyBookingState showAcceptTermsError() => copyWith(showTermsError: true);
+ MyBookingState setError() => copyWith(error: Error());
+
@override
List<Object?> get props => [
booking,
diff --git a/comwell_key_app/lib/my_booking/my_booking_page.dart b/comwell_key_app/lib/my_booking/my_booking_page.dart
index dc01f2cf..69e463fd 100644
--- a/comwell_key_app/lib/my_booking/my_booking_page.dart
+++ b/comwell_key_app/lib/my_booking/my_booking_page.dart
@@ -2,11 +2,15 @@ import 'package:comwell_key_app/booking_details/bloc/booking_details_bloc.dart';
import 'package:comwell_key_app/booking_details/booking_details_repository.dart';
import 'package:comwell_key_app/booking_details/components/share_button.dart';
import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/housekeeping/housekeeping_repository.dart';
import 'package:comwell_key_app/my_booking/components/balance_bottom_sheet.dart';
import 'package:comwell_key_app/my_booking/cubit/my_booking_cubit.dart';
import 'package:comwell_key_app/my_booking/cubit/my_booking_state.dart';
import 'package:comwell_key_app/overview/models/booking.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/profile/profile_repository.dart';
+import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
import 'package:comwell_key_app/utils/locator.dart';
@@ -21,83 +25,94 @@ class MyBookingPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
-
+
return BlocBuilder<MyBookingCubit, MyBookingState>(
- builder: (context, state) {
- final cubit = context.read<MyBookingCubit>();
+ builder: (context, state) {
+ final cubit = context.read<MyBookingCubit>();
- return Scaffold(
- backgroundColor: Colors.white,
- appBar: const ComwellAppBar(
- shouldShowProfileButton: false,
- ),
- body: Stack(
- children: [
- SingleChildScrollView(
- child: Padding(
- padding: const EdgeInsets.all(16.0),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- 'my_booking'.tr(),
- style: theme.textTheme.titleLarge?.copyWith(
- fontWeight: FontWeight.bold,
- color: Colors.black,
+ return BlocListener<PaymentCubit, PaymentProcessingState>(
+ listener: (context, state) async {
+ if (state is PaymentProcessingStateConfirmed) {
+ await Future<void>.delayed(const Duration(seconds: 2));
+ if (!context.mounted) return;
+ Navigator.of(context).popUntil((route) =>
+ route.settings.name == AppRoutes.bookingDetails.name);
+ }
+ },
+ child: Builder(builder: (context) {
+ return Scaffold(
+ backgroundColor: Colors.white,
+ appBar: const ComwellAppBar(
+ shouldShowProfileButton: false,
+ ),
+ body: Stack(
+ children: [
+ SingleChildScrollView(
+ child: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ 'my_booking'.tr(),
+ style: theme.textTheme.titleLarge?.copyWith(
+ fontWeight: FontWeight.bold,
+ color: Colors.black,
+ ),
+ ),
+ const SizedBox(height: 8),
+ Text(
+ 'booking_reference'.tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: colorHeadlineText,
+ ),
),
- ),
- const SizedBox(height: 8),
- Text(
- 'booking_reference'.tr(),
- style: theme.textTheme.bodySmall?.copyWith(
- color: colorHeadlineText,
+ Text(
+ booking.id,
+ style: theme.textTheme.bodyMedium,
),
- ),
- Text(
- booking.id,
- style: theme.textTheme.bodyMedium,
- ),
- const SizedBox(height: 16),
- const Divider(color: colorDivider),
- _buildCheckInOutSection(theme),
- const Divider(color: colorDivider),
- _buildBookingDetails(theme),
- const Divider(color: colorDivider),
- _buildPaymentSection(theme),
- const Divider(color: colorDivider),
- _buildCancellationPolicy(theme),
- const Divider(color: colorDivider),
- const SizedBox(height: 100)
- ],
+ const SizedBox(height: 16),
+ const Divider(color: colorDivider),
+ _buildCheckInOutSection(theme),
+ const Divider(color: colorDivider),
+ _buildBookingDetails(theme),
+ const Divider(color: colorDivider),
+ _buildPaymentSection(theme),
+ const Divider(color: colorDivider),
+ _buildCancellationPolicy(theme),
+ const Divider(color: colorDivider),
+ const SizedBox(height: 100)
+ ],
+ ),
),
),
- ),
- Positioned(
- bottom: 0,
- left: 0,
- right: 0,
- child: GestureDetector(
- onTap: () {
- showModalBottomSheet<void>(
- isScrollControlled: true,
- context: context,
- builder: (context) => BalanceBottomSheet(
- balance: cubit.totalAddonBalance,
- userName: booking.booker.name,
- booking: booking,
- addOnItems: booking.addOnItems ?? [],
- cubit: cubit,
- ),
- );
- },
- child: _buildBalanceBottomSheet(theme, cubit),
+ Positioned(
+ bottom: 0,
+ left: 0,
+ right: 0,
+ child: GestureDetector(
+ onTap: () {
+ showModalBottomSheet<void>(
+ isScrollControlled: true,
+ context: context,
+ builder: (context) => BalanceBottomSheet(
+ balance: cubit.totalAddonBalance,
+ userName: booking.booker.name,
+ booking: booking,
+ addOnItems: booking.addOnItems ?? [],
+ cubit: cubit,
+ ),
+ );
+ },
+ child: _buildBalanceBottomSheet(theme, cubit),
+ ),
),
- ),
- ],
- ),
- );
- }
- );
+ ],
+ ),
+ );
+ }),
+ );
+ });
}
Widget _buildCheckInOutSection(ThemeData theme) {
@@ -201,6 +216,7 @@ class MyBookingPage extends StatelessWidget {
bookingDetailsRepository: locator<BookingDetailsRepository>(),
profileRepository: locator<ProfileRepository>(),
upSaleRepository: locator<UpSalesRepository>(),
+ houseKeepingRepository: locator<HouseKeepingRepository>(),
),
child: ShareButton(
guests: booking.guests,
diff --git a/comwell_key_app/lib/my_booking/pages/my_booking_payment_page.dart b/comwell_key_app/lib/my_booking/pages/my_booking_payment_page.dart
index 08e766b8..51a271db 100644
--- a/comwell_key_app/lib/my_booking/pages/my_booking_payment_page.dart
+++ b/comwell_key_app/lib/my_booking/pages/my_booking_payment_page.dart
@@ -52,7 +52,8 @@ class MyBookingPaymentPage extends StatelessWidget {
padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 24.0, top: 16.0),
child: ElevatedButton(
onPressed: () {
- context.pushNamed(AppRoutes.paymentProcessing.name);
+ context.pushNamed(AppRoutes.paymentProcessing.name);
+ cubit.processPayment();
},
child: Text("pay_bill".tr(),
style: theme.textTheme.bodyMedium
diff --git a/comwell_key_app/lib/payment/cubit/payment_cubit.dart b/comwell_key_app/lib/payment/cubit/payment_cubit.dart
index ede12133..f3e3e9df 100644
--- a/comwell_key_app/lib/payment/cubit/payment_cubit.dart
+++ b/comwell_key_app/lib/payment/cubit/payment_cubit.dart
@@ -49,4 +49,6 @@ class PaymentCubit extends Cubit<PaymentProcessingState> {
void onUserDismissPaymentPopup() {
emit(PaymentProcessingStateNotStarted());
}
+
+
}
diff --git a/comwell_key_app/lib/payment/payment_processing_page.dart b/comwell_key_app/lib/payment/payment_processing_page.dart
index ca5a0867..35b4dc74 100644
--- a/comwell_key_app/lib/payment/payment_processing_page.dart
+++ b/comwell_key_app/lib/payment/payment_processing_page.dart
@@ -1,9 +1,6 @@
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';
@@ -98,7 +95,6 @@ class _PaymentProcessingPageState extends State<PaymentProcessingPage>
color: sandColor[80],
child: BlocListener<PaymentCubit, PaymentProcessingState>(
listener: (context, state) {
- print("qqq state in listener: $state");
if (state is PaymentProcessingStateSessionReceived) {
showAdyenModal(context);
}
@@ -114,7 +110,6 @@ class _PaymentProcessingPageState extends State<PaymentProcessingPage>
case PaymentProcessingStateConfirmed _:
playSuccess();
case PaymentProcessingStateError _:
- print("qqq error in payment processing page");
playError();
default:
playLoading();
diff --git a/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart b/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
index 41a04ff7..c4bd5f65 100644
--- a/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
+++ b/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
@@ -146,12 +146,12 @@ class PreregistrationCubit extends Cubit<PreregistrationState> {
void onProfileContinueClicked() {
if (isFirstNameValid && isLastNameValid && isPhoneNumberValid) {
- final phoneNumber = concatCountryCodeAndPhoneNumber(
- countryCode!, phoneNumberTextController.text);
- final updatedUser = state.user!.copyWith(
- firstName: firstNameTextController.text,
- lastName: lastNameTextController.text,
- phoneNumber: phoneNumber);
+ final phoneNumber = concatCountryCodeAndPhoneNumber(
+ countryCode!, phoneNumberTextController.text);
+ final updatedUser = state.user!.copyWith(
+ firstName: firstNameTextController.text,
+ lastName: lastNameTextController.text,
+ phoneNumber: phoneNumber);
emit(state.copyWith(user: updatedUser));
_navigateNextPage();
@@ -221,9 +221,13 @@ class PreregistrationCubit extends Cubit<PreregistrationState> {
emit(state.copyWith(isLoading: true));
try {
final confirmationId = booking.confirmationId;
+ final hasUpSales = state.addOnUpgrades.any((e) => e.isAddedToCart) ||
+ state.selectedRoomUpgrade.isNotEmpty;
await _profileSettingsRepository.updateUser(state.user!);
- addUpSalesToBooking();
+ if (hasUpSales) {
+ addUpSalesToBooking();
+ }
final preRegResponse = await _preregistrationRepository
.createPreregistration(confirmationId);
@@ -233,9 +237,13 @@ class PreregistrationCubit extends Cubit<PreregistrationState> {
if (!context.mounted) return;
context.pop(preRegResponse);
});
+ } else {
+ emit(state.setError(error: Error()));
+ if (!context.mounted) return;
+ context.pop(null);
}
} catch (e) {
- emit(state.copyWith(isLoading: false));
+ emit(state.setError(error: Error()));
}
}
diff --git a/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart b/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
index 6592fb1c..15af2aee 100644
--- a/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
+++ b/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
@@ -26,6 +26,7 @@ class PreregistrationState extends Equatable {
final bool isAddressValid;
final bool isPostalCodeValid;
final bool isCityValid;
+ final Error? error;
const PreregistrationState({
required this.isLoading,
@@ -46,6 +47,7 @@ class PreregistrationState extends Equatable {
this.isAddressValid = false,
this.isPostalCodeValid = false,
this.isCityValid = false,
+ this.error,
});
PreregistrationState.initial()
@@ -66,7 +68,8 @@ class PreregistrationState extends Equatable {
isLastNameValid = false,
isAddressValid = false,
isPostalCodeValid = false,
- isCityValid = false;
+ isCityValid = false,
+ error = null;
PreregistrationState loaded({required UpSales upSales, required User user}) =>
copyWith(
@@ -107,7 +110,8 @@ class PreregistrationState extends Equatable {
return updateUpgrade(upgrade.copyWith(quantity: quantity));
}
-
+ PreregistrationState setError({required Error error}) =>
+ copyWith(error: error, isLoading: false);
PreregistrationState copyWith({
bool? isLoading,
@@ -130,6 +134,7 @@ class PreregistrationState extends Equatable {
bool? isAddressValid,
bool? isPostalCodeValid,
bool? isCityValid,
+ Error? error,
}) {
return PreregistrationState(
isLoading: isLoading ?? this.isLoading,
@@ -144,6 +149,7 @@ class PreregistrationState extends Equatable {
termsAndConditionsAccepted ?? this.termsAndConditionsAccepted,
forceUpdate: forceUpdate ?? this.forceUpdate,
user: user ?? this.user,
+ error: error ?? this.error,
);
}
@@ -169,5 +175,6 @@ class PreregistrationState extends Equatable {
isCityValid,
availableRoomUpgrades,
selectedRoomUpgrade,
+ error,
];
}
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index ed77678d..69be6581 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -26,6 +26,7 @@ import 'package:comwell_key_app/hotel_information/pages/hotel_information_menu.d
import 'package:comwell_key_app/hotel_information/cubit/hotel_information_cubit.dart';
import 'package:comwell_key_app/hotel_information/hotel_information_page.dart';
import 'package:comwell_key_app/housekeeping/housekeeping_page.dart';
+import 'package:comwell_key_app/housekeeping/housekeeping_repository.dart';
import 'package:comwell_key_app/key/key_page.dart';
import 'package:comwell_key_app/login/login_page.dart';
import 'package:comwell_key_app/my_booking/cubit/my_booking_cubit.dart';
@@ -44,7 +45,6 @@ import 'package:comwell_key_app/payment/payment_processing_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/cubit/preregistration_cubit.dart';
-import 'package:comwell_key_app/pregistration/pregistration_repository.dart';
import 'package:comwell_key_app/pregistration/preregistration_flow.dart';
import 'package:comwell_key_app/profile/cubit/profile_cubit.dart';
import 'package:comwell_key_app/profile/profile_page.dart';
@@ -277,7 +277,9 @@ GoRouter goRouter() {
bookingDetailsRepository:
locator<BookingDetailsRepository>(),
profileRepository: locator<ProfileRepository>(),
- upSaleRepository: locator<UpSalesRepository>()),
+ upSaleRepository: locator<UpSalesRepository>(),
+ houseKeepingRepository:
+ locator<HouseKeepingRepository>()),
child: const BookingDetailsPage(),
);
},
@@ -293,32 +295,31 @@ GoRouter goRouter() {
),
],
),
- GoRoute(
- path: "/${AppRoutes.myBooking.name}",
- name: AppRoutes.myBooking.name,
- builder: (context, state) {
- final booking = state.extra as Booking;
- return BlocProvider(
- create: (context) => MyBookingCubit(
- locator<MyBookingRepository>(),
- initialBooking: booking,
- ),
- child: MyBookingPage(booking: booking),
- );
- }),
- GoRoute(
- path: "/${AppRoutes.payMyBooking.name}",
- name: AppRoutes.payMyBooking.name,
- builder: (context, state) {
- final booking = state.extra as Booking;
- return BlocProvider(
- create: (context) => MyBookingCubit(
- locator<MyBookingRepository>(),
- initialBooking: booking,
- )..init(),
- child: const MyBookingPaymentPage(),
- );
- }),
+ ShellRoute(
+ pageBuilder: (context, state, child) {
+ return NoTransitionPage(
+ child: BlocProvider(
+ create: (context) => MyBookingCubit(
+ locator<MyBookingRepository>(),
+ context.read<PaymentCubit>(),
+ initialBooking: state.extra as Booking)
+ ..init(),
+ child: child));
+ },
+ routes: [
+ GoRoute(
+ path: "/${AppRoutes.myBooking.name}",
+ name: AppRoutes.myBooking.name,
+ builder: (context, state) {
+ return MyBookingPage(booking: state.extra as Booking);
+ }),
+ GoRoute(
+ path: "/${AppRoutes.payMyBooking.name}",
+ name: AppRoutes.payMyBooking.name,
+ builder: (context, state) {
+ return const MyBookingPaymentPage();
+ }),
+ ]),
GoRoute(
path: "/${AppRoutes.paymentCards.name}",
name: AppRoutes.paymentCards.name,
diff --git a/comwell_key_app/lib/utils/locator.dart b/comwell_key_app/lib/utils/locator.dart
index 9fdb0bb6..e333a70c 100644
--- a/comwell_key_app/lib/utils/locator.dart
+++ b/comwell_key_app/lib/utils/locator.dart
@@ -4,6 +4,7 @@ import 'package:comwell_key_app/choose_share_room/choose_share_room_repository.d
import 'package:comwell_key_app/contact/repository/contact_repository.dart';
import 'package:comwell_key_app/database/comwell_db.dart';
import 'package:comwell_key_app/hotel_information/repository/hotel_information_repository.dart';
+import 'package:comwell_key_app/housekeeping/housekeeping_repository.dart';
import 'package:comwell_key_app/key/repository/key_repository.dart';
import 'package:comwell_key_app/my_booking/my_booking_repository.dart';
import 'package:comwell_key_app/notifications/notifications_repository.dart';
@@ -13,6 +14,7 @@ import 'package:comwell_key_app/profile/profile_repository.dart';
import 'package:comwell_key_app/profile_settings/repostiory/profile_settings_repository.dart';
import 'package:comwell_key_app/tracking/comwell_tracking.dart';
import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
+import 'package:comwell_key_app/utils/secure_storage.dart';
import 'package:comwell_key_app/utils/seos_repository.dart';
import 'package:comwell_key_app/routing/app_router.dart';
import 'package:flutter/material.dart';
@@ -63,5 +65,7 @@ void setupLocator() {
locator.registerSingleton<GlobalKey<NavigatorState>>(rootNavigatorKey);
locator.registerFactory<CheckOutRepository>(() => CheckOutRepository());
locator.registerFactory<MyBookingRepository>(() => MyBookingRepository());
+ locator.registerSingleton<SecureStorage>(SecureStorage());
+ locator.registerFactory<HouseKeepingRepository>(() => HouseKeepingRepository());
}
}
diff --git a/comwell_key_app/test/booking_details_test/booking_details_bloc_test.dart b/comwell_key_app/test/booking_details_test/booking_details_bloc_test.dart
index 2bcc45d4..d02a8ea2 100644
--- a/comwell_key_app/test/booking_details_test/booking_details_bloc_test.dart
+++ b/comwell_key_app/test/booking_details_test/booking_details_bloc_test.dart
@@ -2,6 +2,7 @@
import 'package:comwell_key_app/booking_details/bloc/booking_details_bloc.dart';
import 'package:comwell_key_app/booking_details/booking_details_repository.dart';
import 'package:comwell_key_app/check_in/check_in_repository.dart';
+import 'package:comwell_key_app/housekeeping/housekeeping_repository.dart';
import 'package:comwell_key_app/profile/profile_repository.dart';
import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
import 'package:comwell_key_app/utils/locator.dart';
@@ -19,17 +20,21 @@ class MockSeosRepository extends Mock implements SeosRepository {}
class MockUpSalesRepository extends Mock implements UpSalesRepository {}
+class MockHouseKeepingRepository extends Mock implements HouseKeepingRepository {}
+
void main() {
// Declare the mock HomeRepository
late BookingDetailsRepository mockBookingDetailsRepository;
late ProfileRepository mockProfileRepository;
late UpSalesRepository mockUpSalesRepository;
+ late HouseKeepingRepository mockHouseKeepingRepository;
// Setup function runs before every test
setUp(() {
// Initialize the mock HomeRepository
mockBookingDetailsRepository = MockBookingDetailsRepository();
mockProfileRepository = MockProfileRepository();
mockUpSalesRepository = MockUpSalesRepository();
+ mockHouseKeepingRepository = MockHouseKeepingRepository();
setupLocator();
});
@@ -43,6 +48,7 @@ void main() {
bookingDetailsRepository: mockBookingDetailsRepository,
profileRepository: mockProfileRepository,
upSaleRepository: mockUpSalesRepository,
+ houseKeepingRepository: mockHouseKeepingRepository,
);
},
act: (bloc) => bloc.add(InitialEvent()),
@@ -51,3 +57,5 @@ void main() {
// Add more tests for other scenarios and events...
}
+
+