6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit 101033ae
Changed files
comwell_key_app/assets/translations/da-DK.json | 6 +- comwell_key_app/assets/translations/en-US.json | 8 +- .../booking_details/bloc/booking_details_bloc.dart | 4 +- .../lib/my_booking/my_booking_page.dart | 5 +- .../components/approve_conditions_widget.dart | 4 +- .../pregistration/bloc/preregistration_cubit.dart | 331 ---------------- .../pregistration/bloc/preregistration_state.dart | 111 ------ .../components/prereg_bottom_button.dart | 2 +- .../pregistration/cubit/preregistration_cubit.dart | 407 ++++++++++++++++++++ .../pregistration/cubit/preregistration_state.dart | 122 ++++++ .../pregistration/pages/prereg_address_page.dart | 7 +- .../pages/prereg_confirmation_page.dart | 5 +- .../pregistration/pages/prereg_profile_page.dart | 127 +++--- .../pages/prereg_up_sales_catalog_page.dart | 426 ++++++++++++++++++--- .../lib/pregistration/preregistration_flow.dart | 35 +- comwell_key_app/lib/pregistration/utils/utils.dart | 8 +- comwell_key_app/lib/routing/app_router.dart | 10 +- .../components/catalog/other_upgrade_catalog.dart | 15 +- .../components/catalog/room_uprade_catalog.dart | 15 +- .../up_sales/components/comwell_radio_button.dart | 4 +- .../components/confirm_up_sales_dialog.dart | 79 ++++ .../components/up_sales_bottom_button.dart | 35 +- .../components/up_sales_upgrades_widget.dart | 240 ++++++------ .../lib/up_sales/cubit/up_sales_cubit.dart | 22 +- .../lib/up_sales/cubit/up_sales_state.dart | 8 +- .../lib/up_sales/pages/other_upgrade_page.dart | 5 + .../lib/up_sales/pages/room_upgrade_page.dart | 7 +- .../lib/up_sales/up_sale_repository.dart | 372 ------------------ comwell_key_app/lib/up_sales/up_sales_catalog.dart | 83 +++- .../lib/up_sales/up_sales_repository.dart | 372 ++++++++++++++++++ comwell_key_app/lib/utils/locator.dart | 5 +- .../booking_details_bloc_test.dart | 6 + .../test/overview_test/overview_cubic_test.dart | 8 +- .../overview_test/overview_repository_test.dart | 6 +- 34 files changed, 1750 insertions(+), 1150 deletions(-)
Diff
diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index 041480cc..63be253f 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -280,5 +280,9 @@
"see_all_facilities": "Se alle faciliteter",
"remove_from_booking": "Fjern fra booking",
"no_services_available": "Ingen tjenester tilgængelige",
- "no_room_upgrades_available": "Ingen værelsesopgraderinger tilgængelige"
+ "no_room_upgrades_available": "Ingen værelsesopgraderinger tilgængelige",
+ "confirm_up_sales_dialog_title": "Bekræft tilkøb",
+ "confirm_up_sales_dialog_subtitle": "Er du sikker på, at du vil tilføje disse tilkøb for {} kr. til din booking?",
+ "confirm_up_sales_dialog_confirm": "Ja, tilføj tilkøb",
+ "confirm_up_sales_dialog_cancel": "Nej"
}
\ 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 e4be775d..8e56b881 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -28,7 +28,7 @@
"name_cc_sign": "Name",
"become_cc_member_title": "Join comwell club",
"become_cc_member_subtitle": "Join and earn points every time you stay at a Comwell Hotel.",
- "overview_tabbar_active": "Current",
+ "overview_tabbar_active": "Current",
"overview_tabbar_past": "Past",
"overview_tabbar_cancelled": "Cancelled",
"no_past_bookings_title": "No past stays",
@@ -279,6 +279,10 @@
"see_all_facilities": "See all facilities",
"remove_from_booking": "Remove from booking",
"no_services_available": "No services available",
- "no_room_upgrades_available": "No room upgrades available"
+ "no_room_upgrades_available": "No room upgrades available",
+ "confirm_up_sales_dialog_title": "Confirm upgrades",
+ "confirm_up_sales_dialog_subtitle": "Are you sure you want to add these upgrades for {} kr to your booking?",
+ "confirm_up_sales_dialog_confirm": "Yes, add upgrades",
+ "confirm_up_sales_dialog_cancel": "No"
}
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 6730077a..199835cb 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
@@ -6,7 +6,7 @@ import 'package:comwell_key_app/profile/profile_repository.dart';
import 'package:comwell_key_app/profile_settings/model/user.dart';
import 'package:comwell_key_app/up_sales/cubit/up_sales_cubit.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
-import 'package:comwell_key_app/up_sales/up_sale_repository.dart';
+import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
import 'package:comwell_key_app/utils/seos_repository.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
@@ -29,7 +29,7 @@ class BookingDetailsBloc
final ProfileRepository profileRepository;
final SeosRepository seosRepository = locator<SeosRepository>();
Duration _remainingTime = Duration.zero;
- final UpSaleRepository upSaleRepository;
+ final UpSalesRepository upSaleRepository;
List<RoomUpgrade> upSales = [];
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 2ff6df50..93bdd231 100644
--- a/comwell_key_app/lib/my_booking/my_booking_page.dart
+++ b/comwell_key_app/lib/my_booking/my_booking_page.dart
@@ -6,8 +6,7 @@ import 'package:comwell_key_app/my_booking/components/balance_bottom_sheet.dart'
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/profile/profile_repository.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
-import 'package:comwell_key_app/up_sales/cubit/up_sales_cubit.dart';
-import 'package:comwell_key_app/up_sales/up_sale_repository.dart';
+import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
import 'package:comwell_key_app/utils/locator.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@@ -204,7 +203,7 @@ class MyBookingPage extends StatelessWidget {
booking,
bookingDetailsRepository: locator<BookingDetailsRepository>(),
profileRepository: locator<ProfileRepository>(),
- upSaleRepository: locator<UpSaleRepository>(),
+ upSaleRepository: locator<UpSalesRepository>(),
),
child: ShareButton(
guests: booking.guests,
diff --git a/comwell_key_app/lib/payment_cards/components/approve_conditions_widget.dart b/comwell_key_app/lib/payment_cards/components/approve_conditions_widget.dart
index d8a93c2d..ac036379 100644
--- a/comwell_key_app/lib/payment_cards/components/approve_conditions_widget.dart
+++ b/comwell_key_app/lib/payment_cards/components/approve_conditions_widget.dart
@@ -1,5 +1,5 @@
-import 'package:comwell_key_app/pregistration/bloc/preregistration_cubit.dart';
-import 'package:comwell_key_app/pregistration/bloc/preregistration_state.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_cubit.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_state.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/pregistration/bloc/preregistration_cubit.dart b/comwell_key_app/lib/pregistration/bloc/preregistration_cubit.dart
deleted file mode 100644
index a4631991..00000000
--- a/comwell_key_app/lib/pregistration/bloc/preregistration_cubit.dart
+++ /dev/null
@@ -1,331 +0,0 @@
-import 'package:bloc/bloc.dart';
-import 'package:comwell_key_app/overview/models/booking.dart';
-import 'package:comwell_key_app/pregistration/bloc/preregistration_state.dart';
-import 'package:comwell_key_app/pregistration/pregistration_repository.dart';
-import 'package:comwell_key_app/pregistration/utils/utils.dart';
-import 'package:comwell_key_app/profile/profile_repository.dart';
-import 'package:comwell_key_app/profile_settings/model/address.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/tracking/models/analytics_event_item.dart';
-import 'package:comwell_key_app/utils/locator.dart';
-import 'package:comwell_key_app/utils/phone_utils.dart';
-import 'package:country_code_picker/country_code_picker.dart';
-import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter/cupertino.dart';
-import 'package:go_router/go_router.dart';
-
-class PreregistrationCubit extends Cubit<PreregistrationState> {
- final _profileRepository = locator<ProfileRepository>();
- final _profileSettingsRepository = locator<ProfileSettingsRepository>();
- final _tracking = locator<ComwellTracking>();
- final _preregistrationRepository = locator<PreregistrationRepository>();
- final Booking booking;
-
- final pageController = PageController();
- final addressTextController = TextEditingController();
- final postalCodeTextController = TextEditingController();
- final cityTextController = TextEditingController();
- final firstNameTextController = TextEditingController();
- final lastNameTextController = TextEditingController();
- final emailTextController = TextEditingController();
- final phoneNumberTextController = TextEditingController();
-
- CountryCode? countryCode;
- String? phoneNumber;
-
- String selectedCountry = '';
-
- PreregistrationPage get currentPage =>
- PreregistrationPage.fromIndex(pageController.page?.toInt() ?? 0);
- bool _isAnimating = false;
-
- PreregistrationCubit({required this.booking})
- : super(const PreregistrationState(loading: false)) {
- _tracking.trackScreenView(
- "Pre-registration - Betalingskort",
- "/pre-registration/betalingskort",
- );
-
- addressTextController.addListener(() {
- emit(state.copyWith(isAddressValid: isAddressValid));
- });
-
- postalCodeTextController.addListener(() {
- emit(state.copyWith(isPostalCodeValid: isPostalCodeValid));
- });
-
- cityTextController.addListener(() {
- emit(state.copyWith(isCityValid: isCityValid));
- });
- }
-
- void init() async {
- emit(state.copyWith(loading: true, error: null));
- try {
- final user = await _profileRepository.fetchProfileSettings();
- addressTextController.text = user.address.street;
- postalCodeTextController.text = user.address.zipCode;
- cityTextController.text = user.address.city;
- selectedCountry = user.address.country;
-
- countryCode = getCountryCodeFromPhoneNumber(user.phoneNumber).$1;
- phoneNumber = getCountryCodeFromPhoneNumber(user.phoneNumber).$2;
-
- firstNameTextController.text = user.firstName;
- lastNameTextController.text = user.lastName;
- emailTextController.text = user.email;
- phoneNumberTextController.text = phoneNumber!;
-
- emit(state.copyWith(loading: false, error: null, user: user));
- } on Exception catch (e) {
- emit(state.copyWith(error: e));
- }
- }
-
- void onAddressContinueClicked() {
- if (isAddressValid && isCityValid) {
- final updatedUser = state.user!.copyWith(
- address: Address(
- street: addressTextController.text,
- zipCode: postalCodeTextController.text,
- city: cityTextController.text,
- country: selectedCountry,
- ));
-
- emit(state.copyWith(user: updatedUser));
- _navigateNextPage();
- } else {
- emit(state.copyWith(missingInformation: true));
- }
- }
-
- void onProfileContinueClicked() {
- 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();
- }
-
- void onPaymentContinueClicked() {
- _navigateNextPage();
- }
-
- void onUpSalesContinueClicked() {
- _navigateNextPage();
- }
-
- void onContinueClicked(BuildContext context) {
- if (_isAnimating) return;
- switch (currentPage) {
- case PreregistrationPage.profile:
- onProfileContinueClicked();
- break;
- case PreregistrationPage.address:
- onAddressContinueClicked();
- break;
- case PreregistrationPage.payment:
- onPaymentContinueClicked();
- break;
- case PreregistrationPage.upSales:
- onUpSalesContinueClicked();
- break;
- case PreregistrationPage.confirmation:
- _onConfirmPressed(context);
- break;
- }
- }
-
- void addToCart() {
- final analyticsEventItem = AnalyticsEventItem(
- hotelName: "Comwell",
- currency: "DKK",
- value: 500,
- placement: "placement",
- items: ["items"],
- itemId: "itemId",
- itemName: "itemName",
- price: 200,
- quantity: 200);
- _tracking.trackAddToCart(analyticsEventItem);
- }
-
- void removeToCard() {
- final analyticsEventItem = AnalyticsEventItem(
- hotelName: "Comwell",
- currency: "DKK",
- value: 500,
- placement: "placement",
- items: ["items"],
- itemId: "itemId",
- itemName: "itemName",
- price: 200,
- quantity: 200);
- _tracking.trackRemoveFromCart(analyticsEventItem);
- }
-
- void _onConfirmPressed(BuildContext context) async {
- emit(state.copyWith(loading: true));
- try {
- final confirmationId = booking.confirmationId;
-
- await _profileSettingsRepository.updateUser(state.user!);
- final preRegResponse = await _preregistrationRepository
- .createPreregistration(confirmationId);
-
- if (preRegResponse != null) {
- Future.delayed(const Duration(seconds: 3), () {
- emit(state.copyWith(loading: false));
- if (!context.mounted) return;
- context.pop(preRegResponse);
- });
- }
- } catch (e) {
- emit(state.copyWith(loading: false, error: Exception(e)));
- }
- }
-
- void onEditProfileClicked() {
- _navigateTo(PreregistrationPage.profile);
- }
-
- void onEditAddressClicked() {
- _navigateTo(PreregistrationPage.address);
- }
-
- void onEditPaymentMethodCLickked() {
- _navigateTo(PreregistrationPage.payment);
- }
-
- void onEditExtrasClicked() {
- // Not implemented
- }
-
- void onPhoneNumberChanged(String phoneNumber) {
- phoneNumberTextController.text = phoneNumber;
- emit(state.copyWith(isPhoneNumberValid: isPhoneNumberValid));
- }
-
- void onCountryCodeSelected(CountryCode countryCode) {
- countryCode = countryCode;
- }
-
- bool onBackClicked() {
- if (_isAnimating) return true;
- final hasPage = pageController.page != null;
- if (hasPage && pageController.page! >= 1.0) {
- _navigatePreviousPage();
- return true;
- }
- return false;
- }
-
- void _navigateTo(PreregistrationPage page) async {
- if (_isAnimating) return;
- _isAnimating = true;
- await pageController.animateToPage(page.index,
- duration: const Duration(milliseconds: 500),
- curve: Curves.fastOutSlowIn);
- emit(state.copyWith(forceUpdate: true));
- _isAnimating = false;
- }
-
- void _navigateNextPage() async {
- if (_isAnimating) return;
- _isAnimating = true;
- await pageController.nextPage(
- duration: const Duration(milliseconds: 500),
- curve: Curves.fastOutSlowIn);
- emit(state.copyWith(forceUpdate: true));
- _isAnimating = false;
- }
-
- void _navigatePreviousPage() async {
- if (_isAnimating) return;
- _isAnimating = true;
- await pageController.previousPage(
- duration: const Duration(milliseconds: 500),
- curve: Curves.fastOutSlowIn);
- emit(state.copyWith(forceUpdate: true));
- _isAnimating = false;
- }
-
- @override
- Future<void> close() {
- addressTextController.dispose();
- postalCodeTextController.dispose();
- cityTextController.dispose();
- pageController.dispose();
- return super.close();
- }
-
- bool get isAddressValid => addressTextController.text.length > 0;
-
- bool get isPostalCodeValid => postalCodeTextController.text.length > 0;
-
- bool get isCityValid => cityTextController.text.length > 0;
-
- bool get isPhoneNumberValid =>
- phoneNumberTextController.text.isNotEmpty &&
- phoneNumberTextController.text.length > 8 &&
- phoneNumberTextController.text.length < 16;
-
- bool get isFirstNameValid => firstNameTextController.text.isNotEmpty;
-
- bool get isLastNameValid => lastNameTextController.text.isNotEmpty;
-
- bool get canContinue {
- int page = pageController.page?.ceil() ?? 0;
-
- final preregPage = PreregistrationPage.fromIndex(page);
-
- print("isAddressValid: $isAddressValid");
- print("isPostalCodeValid: $isPostalCodeValid");
- print("isCityValid: $isCityValid");
- print("isPhoneNumberValid: $isPhoneNumberValid");
- print("isFirstNameValid: $isFirstNameValid");
- print("isLastNameValid: $isLastNameValid");
- print("state.isTermsAccepted: ${state.isTermsAccepted}");
- switch (preregPage) {
- case PreregistrationPage.profile:
- return isFirstNameValid && isLastNameValid && isPhoneNumberValid;
- case PreregistrationPage.address:
- return isAddressValid && isPostalCodeValid && isCityValid;
- case PreregistrationPage.payment:
- return state.isTermsAccepted;
- case PreregistrationPage.upSales:
- return true;
- case PreregistrationPage.confirmation:
- return true;
- }
- }
-
- String get buttonText {
- int page = pageController.page?.ceil() ?? 0;
- final preregPage = PreregistrationPage.fromIndex(page);
- switch (preregPage) {
- case PreregistrationPage.profile:
- return "generic_continue".tr();
- case PreregistrationPage.address:
- return "generic_continue".tr();
- case PreregistrationPage.payment:
- return "generic_continue".tr();
- case PreregistrationPage.upSales:
- return state.selectedUpSales.isEmpty
- ? "continue_without_up_sales".tr()
- : "generic_continue".tr();
- case PreregistrationPage.confirmation:
- return "generic_confirm".tr();
- }
- }
-
- void onTermsAndConditionsToggled(bool toggle) {
- emit(state.copyWith(isTermsAccepted: toggle));
- }
-}
diff --git a/comwell_key_app/lib/pregistration/bloc/preregistration_state.dart b/comwell_key_app/lib/pregistration/bloc/preregistration_state.dart
deleted file mode 100644
index 52cac5bf..00000000
--- a/comwell_key_app/lib/pregistration/bloc/preregistration_state.dart
+++ /dev/null
@@ -1,111 +0,0 @@
-import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
-import 'package:country_code_picker/country_code_picker.dart';
-import 'package:equatable/equatable.dart';
-
-import '../../profile_settings/model/user.dart';
-
-class PreregistrationState extends Equatable {
- final bool forceUpdate;
- final bool loading;
- final User? user;
- final CountryCode? countryCode;
- final String? phoneNumber;
- final Exception? error;
- final bool missingInformation;
- final int numOfExtras;
- final int extrasTotalPrice;
- final bool termsAndConditionsAccepted;
- final bool isPhoneNumberValid;
- final bool isFirstNameValid;
- final bool isLastNameValid;
- final bool isTermsAccepted;
- final bool isAddressValid;
- final bool isPostalCodeValid;
- final bool isCityValid;
- final List<RoomUpgrade> selectedUpSales;
-
- const PreregistrationState({
- required this.loading,
- this.missingInformation = false,
- this.numOfExtras = 0,
- this.extrasTotalPrice = 0,
- this.termsAndConditionsAccepted = false,
- this.forceUpdate = false,
- this.user,
- this.error,
- this.phoneNumber,
- this.countryCode,
- this.isPhoneNumberValid = false,
- this.isFirstNameValid = false,
- this.isLastNameValid = false,
- this.isTermsAccepted = false,
- this.isAddressValid = false,
- this.isPostalCodeValid = false,
- this.isCityValid = false,
- this.selectedUpSales = const [],
- });
-
- @override
- List<Object?> get props => [
- loading,
- user,
- error,
- phoneNumber,
- countryCode,
- missingInformation,
- numOfExtras,
- extrasTotalPrice,
- termsAndConditionsAccepted,
- forceUpdate,
- isPhoneNumberValid,
- isFirstNameValid,
- isLastNameValid,
- isTermsAccepted,
- isAddressValid,
- isPostalCodeValid,
- isCityValid,
- selectedUpSales,
- ];
-
- PreregistrationState copyWith({
- bool? loading,
- User? user,
- Exception? error,
- String? phoneNumber,
- bool? missingInformation,
- int? numOfExtras,
- int? extrasTotalPrice,
- String? buttonTextStringId,
- bool? termsAndConditionsAccepted,
- bool forceUpdate = false,
- bool? isPhoneNumberValid,
- bool? isFirstNameValid,
- bool? isLastNameValid,
- bool? isTermsAccepted,
- bool? isAddressValid,
- bool? isPostalCodeValid,
- bool? isCityValid,
- List<RoomUpgrade>? selectedUpSales,
- }) {
- return PreregistrationState(
- forceUpdate: forceUpdate ? !this.forceUpdate : this.forceUpdate,
- loading: loading ?? this.loading,
- missingInformation: missingInformation ?? this.missingInformation,
- user: user ?? this.user,
- numOfExtras: numOfExtras ?? this.numOfExtras,
- termsAndConditionsAccepted:
- termsAndConditionsAccepted ?? this.termsAndConditionsAccepted,
- extrasTotalPrice: extrasTotalPrice ?? this.extrasTotalPrice,
- error: error,
- phoneNumber: phoneNumber ?? this.phoneNumber,
- countryCode: countryCode,
- isPhoneNumberValid: isPhoneNumberValid ?? this.isPhoneNumberValid,
- isFirstNameValid: isFirstNameValid ?? this.isFirstNameValid,
- isLastNameValid: isLastNameValid ?? this.isLastNameValid,
- isTermsAccepted: isTermsAccepted ?? this.isTermsAccepted,
- isAddressValid: isAddressValid ?? this.isAddressValid,
- isPostalCodeValid: isPostalCodeValid ?? this.isPostalCodeValid,
- isCityValid: isCityValid ?? this.isCityValid,
- selectedUpSales: selectedUpSales ?? this.selectedUpSales);
- }
-}
diff --git a/comwell_key_app/lib/pregistration/components/prereg_bottom_button.dart b/comwell_key_app/lib/pregistration/components/prereg_bottom_button.dart
index 935709c6..db1d1e2d 100644
--- a/comwell_key_app/lib/pregistration/components/prereg_bottom_button.dart
+++ b/comwell_key_app/lib/pregistration/components/prereg_bottom_button.dart
@@ -1,4 +1,4 @@
-import 'package:comwell_key_app/pregistration/bloc/preregistration_cubit.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_cubit.dart';
import 'package:flutter/material.dart';
class PreregBottomButton extends StatelessWidget {
diff --git a/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart b/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
new file mode 100644
index 00000000..f5adfdfd
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
@@ -0,0 +1,407 @@
+import 'package:bloc/bloc.dart';
+import 'package:comwell_key_app/overview/models/booking.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_state.dart';
+import 'package:comwell_key_app/pregistration/pregistration_repository.dart';
+import 'package:comwell_key_app/pregistration/utils/utils.dart';
+import 'package:comwell_key_app/profile/profile_repository.dart';
+import 'package:comwell_key_app/profile_settings/model/address.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/tracking/models/analytics_event_item.dart';
+import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
+import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
+import 'package:comwell_key_app/utils/locator.dart';
+import 'package:comwell_key_app/utils/phone_utils.dart';
+import 'package:country_code_picker/country_code_picker.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:go_router/go_router.dart';
+
+class PreregistrationCubit extends Cubit<PreregistrationState> {
+ final _profileRepository = locator<ProfileRepository>();
+ final _profileSettingsRepository = locator<ProfileSettingsRepository>();
+ final _tracking = locator<ComwellTracking>();
+ final _preregistrationRepository = locator<PreregistrationRepository>();
+ final _upSalesRepository = locator<UpSalesRepository>();
+
+ final Booking booking;
+ List<RoomUpgrade> upSales = [];
+
+ final pageController = PageController();
+ final addressTextController = TextEditingController();
+ final postalCodeTextController = TextEditingController();
+ final cityTextController = TextEditingController();
+ final firstNameTextController = TextEditingController();
+ final lastNameTextController = TextEditingController();
+ final emailTextController = TextEditingController();
+ final phoneNumberTextController = TextEditingController();
+
+ CountryCode? countryCode;
+ String? phoneNumber;
+
+ String selectedCountry = '';
+
+ PreregistrationPage get currentPage =>
+ PreregistrationPage.fromIndex(pageController.page?.toInt() ?? 0);
+ bool _isAnimating = false;
+
+ PreregistrationCubit({required this.booking})
+ : super(const PreregistrationState(
+ isLoading: false,
+ selected: false,
+ upSales: [],
+ selectedUpSales: [])) {
+ _tracking.trackScreenView(
+ "Pre-registration - Betalingskort",
+ "/pre-registration/betalingskort",
+ );
+
+ addressTextController.addListener(() {
+ emit(state.copyWith(isAddressValid: isAddressValid));
+ });
+
+ postalCodeTextController.addListener(() {
+ emit(state.copyWith(isPostalCodeValid: isPostalCodeValid));
+ });
+
+ cityTextController.addListener(() {
+ emit(state.copyWith(isCityValid: isCityValid));
+ });
+ }
+
+ void init() async {
+ emit(state.copyWith(isLoading: true, error: null));
+ try {
+ final user = await _profileRepository.fetchProfileSettings();
+ addressTextController.text = "Bernard Bangs Alle 25";
+ postalCodeTextController.text = "2000";
+ cityTextController.text = "Copenhagen";
+ selectedCountry = "DK";
+
+ countryCode = getCountryCodeFromPhoneNumber(user.phoneNumber).$1;
+ phoneNumber = getCountryCodeFromPhoneNumber(user.phoneNumber).$2;
+
+ firstNameTextController.text = user.firstName;
+ lastNameTextController.text = user.lastName;
+ emailTextController.text = user.email;
+ phoneNumberTextController.text = "701234567";
+
+ upSales = await _upSalesRepository.getMockUpSales();
+
+ emit(state.copyWith(
+ isLoading: false, error: null, user: user, upSales: upSales));
+ } on Exception catch (e) {
+ emit(state.copyWith(error: e));
+ }
+ }
+
+ void onAddressContinueClicked() {
+ if (isAddressValid && isCityValid) {
+ final updatedUser = state.user!.copyWith(
+ address: Address(
+ street: addressTextController.text,
+ zipCode: postalCodeTextController.text,
+ city: cityTextController.text,
+ country: selectedCountry,
+ ));
+
+ emit(state.copyWith(user: updatedUser));
+ _navigateNextPage();
+ } else {
+ emit(state.copyWith(missingInformation: true));
+ }
+ }
+
+ void onProfileContinueClicked() {
+ 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();
+ }
+
+ void onPaymentContinueClicked() {
+ _navigateNextPage();
+ }
+
+ void onUpSalesContinueClicked() {
+ emit(state.copyWith(
+ selectedUpSales: state.selectedUpSales,
+ numOfExtras: state.selectedUpSales.length,
+ extrasTotalPrice: extrasTotalPrice));
+
+ _navigateNextPage();
+ }
+
+ void onContinueClicked(BuildContext context) {
+ if (_isAnimating) return;
+ switch (currentPage) {
+ case PreregistrationPage.profile:
+ onProfileContinueClicked();
+ break;
+ case PreregistrationPage.address:
+ onAddressContinueClicked();
+ break;
+ case PreregistrationPage.payment:
+ onPaymentContinueClicked();
+ break;
+ case PreregistrationPage.upSales:
+ onUpSalesContinueClicked();
+ break;
+ case PreregistrationPage.confirmation:
+ _onConfirmPressed(context);
+ break;
+ }
+ }
+
+ void addToCart() {
+ final analyticsEventItem = AnalyticsEventItem(
+ hotelName: "Comwell",
+ currency: "DKK",
+ value: 500,
+ placement: "placement",
+ items: ["items"],
+ itemId: "itemId",
+ itemName: "itemName",
+ price: 200,
+ quantity: 200);
+ _tracking.trackAddToCart(analyticsEventItem);
+ }
+
+ void removeToCard() {
+ final analyticsEventItem = AnalyticsEventItem(
+ hotelName: "Comwell",
+ currency: "DKK",
+ value: 500,
+ placement: "placement",
+ items: ["items"],
+ itemId: "itemId",
+ itemName: "itemName",
+ price: 200,
+ quantity: 200);
+ _tracking.trackRemoveFromCart(analyticsEventItem);
+ }
+
+ void _onConfirmPressed(BuildContext context) async {
+ emit(state.copyWith(isLoading: true));
+ try {
+ final confirmationId = booking.confirmationId;
+
+ await _profileSettingsRepository.updateUser(state.user!);
+ final preRegResponse = await _preregistrationRepository
+ .createPreregistration(confirmationId);
+
+ if (preRegResponse != null) {
+ Future.delayed(const Duration(seconds: 3), () {
+ emit(state.copyWith(isLoading: false));
+ if (!context.mounted) return;
+ context.pop(preRegResponse);
+ });
+ }
+ } catch (e) {
+ emit(state.copyWith(isLoading: false, error: Exception(e)));
+ }
+ }
+
+ void onEditProfileClicked() {
+ _navigateTo(PreregistrationPage.profile);
+ }
+
+ void onEditAddressClicked() {
+ _navigateTo(PreregistrationPage.address);
+ }
+
+ void onEditPaymentMethodCLickked() {
+ _navigateTo(PreregistrationPage.payment);
+ }
+
+ void onEditExtrasClicked() {
+ _navigateTo(PreregistrationPage.upSales);
+ }
+
+ void onPhoneNumberChanged(String phoneNumber) {
+ phoneNumberTextController.text = phoneNumber;
+ emit(state.copyWith(isPhoneNumberValid: isPhoneNumberValid));
+ }
+
+ void onCountryCodeSelected(CountryCode countryCode) {
+ countryCode = countryCode;
+ }
+
+ bool onBackClicked() {
+ if (_isAnimating) return true;
+ final hasPage = pageController.page != null;
+ if (hasPage && pageController.page! >= 1.0) {
+ _navigatePreviousPage();
+ return true;
+ }
+ return false;
+ }
+
+ void _navigateTo(PreregistrationPage page) async {
+ if (_isAnimating) return;
+ _isAnimating = true;
+ await pageController.animateToPage(page.index,
+ duration: const Duration(milliseconds: 500),
+ curve: Curves.fastOutSlowIn);
+ emit(state.copyWith(forceUpdate: true));
+ _isAnimating = false;
+ }
+
+ void _navigateNextPage() async {
+ if (_isAnimating) return;
+ _isAnimating = true;
+ await pageController.nextPage(
+ duration: const Duration(milliseconds: 500),
+ curve: Curves.fastOutSlowIn);
+ emit(state.copyWith(forceUpdate: true));
+ _isAnimating = false;
+ }
+
+ void _navigatePreviousPage() async {
+ if (_isAnimating) return;
+ _isAnimating = true;
+ await pageController.previousPage(
+ duration: const Duration(milliseconds: 500),
+ curve: Curves.fastOutSlowIn);
+ emit(state.copyWith(forceUpdate: true));
+ _isAnimating = false;
+ }
+
+ int get extrasTotalPrice {
+ return state.selectedUpSales
+ .fold(0, (sum, upgrade) => sum + int.parse(upgrade.price));
+ }
+
+ @override
+ Future<void> close() {
+ addressTextController.dispose();
+ postalCodeTextController.dispose();
+ cityTextController.dispose();
+ pageController.dispose();
+ firstNameTextController.dispose();
+ lastNameTextController.dispose();
+ emailTextController.dispose();
+ phoneNumberTextController.dispose();
+ return super.close();
+ }
+
+ bool get isAddressValid => addressTextController.text.isNotEmpty;
+
+ bool get isPostalCodeValid => postalCodeTextController.text.isNotEmpty;
+
+ bool get isCityValid => cityTextController.text.isNotEmpty;
+
+ bool get isPhoneNumberValid =>
+ phoneNumberTextController.text.length > 8 &&
+ phoneNumberTextController.text.length < 16;
+
+ bool get isFirstNameValid => firstNameTextController.text.isNotEmpty;
+
+ bool get isLastNameValid => lastNameTextController.text.isNotEmpty;
+
+ bool get canContinue {
+ int page = pageController.page?.ceil() ?? 0;
+
+ final preregPage = PreregistrationPage.fromIndex(page);
+
+ switch (preregPage) {
+ case PreregistrationPage.profile:
+ return isFirstNameValid && isLastNameValid && isPhoneNumberValid;
+ case PreregistrationPage.address:
+ return isAddressValid && isPostalCodeValid && isCityValid;
+ case PreregistrationPage.payment:
+ return state.isTermsAccepted;
+ case PreregistrationPage.upSales:
+ return true;
+ case PreregistrationPage.confirmation:
+ return true;
+ }
+ }
+
+ String get buttonText {
+ int page = pageController.page?.ceil() ?? 0;
+ final preregPage = PreregistrationPage.fromIndex(page);
+ switch (preregPage) {
+ case PreregistrationPage.profile:
+ return "generic_continue".tr();
+ case PreregistrationPage.address:
+ return "generic_continue".tr();
+ case PreregistrationPage.payment:
+ return "generic_continue".tr();
+ case PreregistrationPage.upSales:
+ if (state.selectedUpSales.isEmpty) {
+ return "continue_without_up_sales".tr();
+ }
+ return "generic_continue".tr();
+ case PreregistrationPage.confirmation:
+ return "generic_confirm".tr();
+ }
+ }
+
+ void onTermsAndConditionsToggled(bool toggle) {
+ emit(state.copyWith(isTermsAccepted: toggle));
+ }
+
+ void addSelected(RoomUpgrade roomUpgrade) {
+ // If the new upgrade is of type "room", remove any existing room upgrades
+ if (roomUpgrade.type == UpgradeType.room) {
+ final filteredUpSales = state.selectedUpSales
+ .where((upgrade) => upgrade.type != UpgradeType.room)
+ .toList();
+
+ emit(state.copyWith(selectedUpSales: [...filteredUpSales, roomUpgrade]));
+ } else {
+ // For non-room upgrades, just add to the list
+ emit(state
+ .copyWith(selectedUpSales: [...state.selectedUpSales, roomUpgrade]));
+ }
+ }
+
+ void increment() {
+ emit(state.copyWith(quantity: state.quantity + 1));
+ }
+
+ void decrement() {
+ if (state.quantity > 0 || state.selectedUpSales.length > 0) {
+ emit(state.copyWith(quantity: state.quantity - 1));
+ }
+ }
+
+ void onContinue() {
+ emit(state.copyWith(selected: false));
+ }
+
+ void updateUpgradeQuantity(RoomUpgrade roomUpgrade, int quantity) {
+ if (quantity == 0) {
+ // Remove all instances of this upgrade from selected upgrades
+ final filteredUpSales = state.selectedUpSales
+ .where((upgrade) => upgrade.id != roomUpgrade.id)
+ .toList();
+ emit(state.copyWith(selectedUpSales: filteredUpSales));
+ return;
+ } else {
+ final existingItems = state.selectedUpSales.where((upgrade) => upgrade.id != roomUpgrade.id).toList();
+ final newSelectedUpSales = [...existingItems, ...List.generate(quantity, (_) => roomUpgrade)];
+ emit(state.copyWith(selectedUpSales: newSelectedUpSales));
+ }
+ }
+
+ void removeUpgrade(RoomUpgrade roomUpgrade) {
+ emit(state.copyWith(
+ selectedUpSales: state.selectedUpSales
+ .where((upgrade) => upgrade.id != roomUpgrade.id)
+ .toList()));
+ }
+
+ int extrasTotalQuantity(RoomUpgrade roomUpgrade) {
+ return state.selectedUpSales
+ .where((element) => element.id == roomUpgrade.id)
+ .length;
+ }
+}
diff --git a/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart b/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
new file mode 100644
index 00000000..65396a9d
--- /dev/null
+++ b/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
@@ -0,0 +1,122 @@
+
+import 'package:comwell_key_app/up_sales/cubit/up_sales_state.dart';
+import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
+import 'package:country_code_picker/country_code_picker.dart';
+import 'package:equatable/equatable.dart';
+
+import '../../profile_settings/model/user.dart';
+
+class PreregistrationState extends UpSalesState {
+ final bool forceUpdate;
+ final User? user;
+ final CountryCode? countryCode;
+ final String? phoneNumber;
+ final bool missingInformation;
+ @override
+ final Exception? error;
+ final int numOfExtras;
+ final int extrasTotalPrice;
+ final bool termsAndConditionsAccepted;
+ final bool isPhoneNumberValid;
+ final bool isFirstNameValid;
+ final bool isLastNameValid;
+ final bool isTermsAccepted;
+ final bool isAddressValid;
+ final bool isPostalCodeValid;
+ final bool isCityValid;
+
+ const PreregistrationState({
+ required super.isLoading,
+ required super.selected,
+ required super.upSales,
+ required super.selectedUpSales,
+ this.error,
+ this.missingInformation = false,
+ this.numOfExtras = 0,
+ this.extrasTotalPrice = 0,
+ this.termsAndConditionsAccepted = false,
+ this.forceUpdate = false,
+ this.user,
+ this.phoneNumber,
+ this.countryCode,
+ this.isPhoneNumberValid = false,
+ this.isFirstNameValid = false,
+ this.isLastNameValid = false,
+ this.isTermsAccepted = false,
+ this.isAddressValid = false,
+ this.isPostalCodeValid = false,
+ this.isCityValid = false,
+ });
+
+ @override
+ List<Object?> get props => [
+ super.isLoading,
+ error,
+ user,
+ phoneNumber,
+ countryCode,
+ missingInformation,
+ numOfExtras,
+ extrasTotalPrice,
+ termsAndConditionsAccepted,
+ forceUpdate,
+ isPhoneNumberValid,
+ isFirstNameValid,
+ isLastNameValid,
+ isTermsAccepted,
+ isAddressValid,
+ isPostalCodeValid,
+ isCityValid,
+ selectedUpSales,
+ upSales,
+ ];
+ @override
+ PreregistrationState copyWith({
+ bool? selected,
+ List<RoomUpgrade>? upSales,
+ List<RoomUpgrade>? selectedUpSales,
+ bool? isLoading,
+ Exception? error,
+ int? quantity,
+ User? user,
+ String? phoneNumber,
+ bool? missingInformation,
+ int? numOfExtras,
+ int? extrasTotalPrice,
+ String? buttonTextStringId,
+ bool? termsAndConditionsAccepted,
+ bool forceUpdate = false,
+ bool? isPhoneNumberValid,
+ bool? isFirstNameValid,
+ bool? isLastNameValid,
+ bool? isTermsAccepted,
+ bool? isAddressValid,
+ bool? isPostalCodeValid,
+ bool? isCityValid
+ }) {
+ return PreregistrationState(
+ selected: selected ?? super.selected,
+ isLoading: isLoading ?? super.isLoading,
+ error: error ?? this.error,
+ forceUpdate: forceUpdate ? !this.forceUpdate : this.forceUpdate,
+ missingInformation: missingInformation ?? this.missingInformation,
+ user: user ?? this.user,
+ numOfExtras: numOfExtras ?? this.numOfExtras,
+ termsAndConditionsAccepted:
+ termsAndConditionsAccepted ?? this.termsAndConditionsAccepted,
+ extrasTotalPrice: extrasTotalPrice ?? this.extrasTotalPrice,
+ phoneNumber: phoneNumber ?? this.phoneNumber,
+ countryCode: countryCode,
+ isPhoneNumberValid: isPhoneNumberValid ?? this.isPhoneNumberValid,
+ isFirstNameValid: isFirstNameValid ?? this.isFirstNameValid,
+ isLastNameValid: isLastNameValid ?? this.isLastNameValid,
+ isTermsAccepted: isTermsAccepted ?? this.isTermsAccepted,
+ isAddressValid: isAddressValid ?? this.isAddressValid,
+ isPostalCodeValid: isPostalCodeValid ?? this.isPostalCodeValid,
+ isCityValid: isCityValid ?? this.isCityValid,
+ selectedUpSales: selectedUpSales ?? this.selectedUpSales,
+ upSales: upSales ?? this.upSales,
+ );
+ }
+
+}
diff --git a/comwell_key_app/lib/pregistration/pages/prereg_address_page.dart b/comwell_key_app/lib/pregistration/pages/prereg_address_page.dart
index fd0dd5e5..337ce0d8 100644
--- a/comwell_key_app/lib/pregistration/pages/prereg_address_page.dart
+++ b/comwell_key_app/lib/pregistration/pages/prereg_address_page.dart
@@ -1,6 +1,6 @@
import 'package:comwell_key_app/common/components/comwell_text_field.dart';
-import 'package:comwell_key_app/pregistration/bloc/preregistration_cubit.dart';
-import 'package:comwell_key_app/pregistration/bloc/preregistration_state.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_cubit.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_state.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:country_code_picker/country_code_picker.dart';
import 'package:easy_localization/easy_localization.dart';
@@ -16,7 +16,7 @@ class PreregAddressPage extends StatelessWidget {
builder: (context, state) {
final cubit = context.read<PreregistrationCubit>();
- if (state.loading) {
+ if (state.isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (state.error != null) {
@@ -34,6 +34,7 @@ class PreregAddressPage extends StatelessWidget {
? "generic_information_required".tr()
: null;
return ListView(
+ padding: const EdgeInsets.symmetric(horizontal: 12.0),
key: const PageStorageKey("information_form"),
children: [
const SizedBox(height: 40),
diff --git a/comwell_key_app/lib/pregistration/pages/prereg_confirmation_page.dart b/comwell_key_app/lib/pregistration/pages/prereg_confirmation_page.dart
index d71ae608..2949c5ff 100644
--- a/comwell_key_app/lib/pregistration/pages/prereg_confirmation_page.dart
+++ b/comwell_key_app/lib/pregistration/pages/prereg_confirmation_page.dart
@@ -1,4 +1,4 @@
-import 'package:comwell_key_app/pregistration/bloc/preregistration_cubit.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_cubit.dart';
import 'package:comwell_key_app/pregistration/components/information_card.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:easy_localization/easy_localization.dart';
@@ -26,6 +26,7 @@ class PreregConfirmationPage extends StatelessWidget {
return SafeArea(
child: ListView(
+ padding: const EdgeInsets.symmetric(horizontal: 12.0),
children: [
const SizedBox(height: 16),
Text("preregistration_confirmation_title".tr(),
@@ -122,7 +123,7 @@ class PreregConfirmationPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
- "${state.extrasTotalPrice} kr.",
+ "${cubit.extrasTotalPrice} kr.",
style: theme.textTheme.bodyMedium
),
Text(
diff --git a/comwell_key_app/lib/pregistration/pages/prereg_profile_page.dart b/comwell_key_app/lib/pregistration/pages/prereg_profile_page.dart
index 3e1ef54b..54d0106d 100644
--- a/comwell_key_app/lib/pregistration/pages/prereg_profile_page.dart
+++ b/comwell_key_app/lib/pregistration/pages/prereg_profile_page.dart
@@ -1,7 +1,7 @@
import 'package:comwell_key_app/common/components/comwell_text_field.dart';
import 'package:comwell_key_app/profile_settings/components/intl_phone_field.dart';
-import 'package:comwell_key_app/pregistration/bloc/preregistration_cubit.dart';
-import 'package:comwell_key_app/pregistration/bloc/preregistration_state.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_cubit.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_state.dart';
import 'package:country_code_picker/country_code_picker.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@@ -15,7 +15,7 @@ class PreregProfilePage extends StatelessWidget {
final theme = Theme.of(context);
return BlocBuilder<PreregistrationCubit, PreregistrationState>(
builder: (context, state) {
- if (state.loading) {
+ if (state.isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (state.user != null) {
@@ -49,65 +49,68 @@ class PreregProfilePage extends StatelessWidget {
: null;
return ListView(children: [
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- const SizedBox(height: 36),
- Text(
- "profile_settings".tr(),
- style: theme.textTheme.headlineLarge,
- textAlign: TextAlign.start,
- ),
- const SizedBox(height: 36),
- ComwellTextField(
- key: const Key("firstName"),
- fieldName: "profile_settings_firstname".tr(),
- initialValue: state.user!.firstName,
- readOnly: false,
- controller: cubit.firstNameTextController,
- errorMessage: firstNameErrorMessage,
- onChanged: (value) {
- cubit.firstNameTextController.text = value;
- },
- ),
- const SizedBox(height: 8),
- ComwellTextField(
- key: const Key("lastName"),
- fieldName: "profile_settings_lastname".tr(),
- initialValue: state.user!.lastName,
- readOnly: false,
- controller: cubit.lastNameTextController,
- errorMessage: lastNameErrorMessage,
- onChanged: (value) {
- cubit.lastNameTextController.text = value;
- },
- ),
- const SizedBox(height: 8),
- ComwellTextField(
- key: const Key("email"),
- fieldName: "profile_settings_email".tr(),
- initialValue: state.user!.email,
- readOnly: true,
- controller: cubit.emailTextController,
- ),
- const SizedBox(height: 8),
- IntlPhoneField(
- key: const Key("phone"),
- title: "profile_settings_phone".tr(),
- phoneNumber: cubit.phoneNumber!,
- countryCode: cubit.countryCode!,
- controller: cubit.phoneNumberTextController,
- readOnly: false,
- errorMessage: phoneNumberErrorMessage,
- onCountryCodeSelected: (CountryCode countryCode) {
- cubit.onCountryCodeSelected(countryCode);
- },
- onPhoneNumberChanged: (String phoneNumber) {
- cubit.onPhoneNumberChanged(phoneNumber);
- },
- onSubmitted: (_) {},
- ),
- ],
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 12.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(height: 36),
+ Text(
+ "profile_settings".tr(),
+ style: theme.textTheme.headlineLarge,
+ textAlign: TextAlign.start,
+ ),
+ const SizedBox(height: 36),
+ ComwellTextField(
+ key: const Key("firstName"),
+ fieldName: "profile_settings_firstname".tr(),
+ initialValue: state.user!.firstName,
+ readOnly: false,
+ controller: cubit.firstNameTextController,
+ errorMessage: firstNameErrorMessage,
+ onChanged: (value) {
+ cubit.firstNameTextController.text = value;
+ },
+ ),
+ const SizedBox(height: 8),
+ ComwellTextField(
+ key: const Key("lastName"),
+ fieldName: "profile_settings_lastname".tr(),
+ initialValue: state.user!.lastName,
+ readOnly: false,
+ controller: cubit.lastNameTextController,
+ errorMessage: lastNameErrorMessage,
+ onChanged: (value) {
+ cubit.lastNameTextController.text = value;
+ },
+ ),
+ const SizedBox(height: 8),
+ ComwellTextField(
+ key: const Key("email"),
+ fieldName: "profile_settings_email".tr(),
+ initialValue: state.user!.email,
+ readOnly: true,
+ controller: cubit.emailTextController,
+ ),
+ const SizedBox(height: 8),
+ IntlPhoneField(
+ key: const Key("phone"),
+ title: "profile_settings_phone".tr(),
+ phoneNumber: cubit.phoneNumber!,
+ countryCode: cubit.countryCode!,
+ controller: cubit.phoneNumberTextController,
+ readOnly: false,
+ errorMessage: phoneNumberErrorMessage,
+ onCountryCodeSelected: (CountryCode countryCode) {
+ cubit.onCountryCodeSelected(countryCode);
+ },
+ onPhoneNumberChanged: (String phoneNumber) {
+ cubit.onPhoneNumberChanged(phoneNumber);
+ },
+ onSubmitted: (_) {},
+ ),
+ ],
+ ),
),
]);
}
diff --git a/comwell_key_app/lib/pregistration/pages/prereg_up_sales_catalog_page.dart b/comwell_key_app/lib/pregistration/pages/prereg_up_sales_catalog_page.dart
index e44dd426..76cebbc0 100644
--- a/comwell_key_app/lib/pregistration/pages/prereg_up_sales_catalog_page.dart
+++ b/comwell_key_app/lib/pregistration/pages/prereg_up_sales_catalog_page.dart
@@ -1,12 +1,18 @@
+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/components/catalog/other_upgrade_catalog.dart';
import 'package:comwell_key_app/up_sales/components/catalog/room_uprade_catalog.dart';
import 'package:comwell_key_app/up_sales/components/catalog/service_catalog.dart';
import 'package:comwell_key_app/up_sales/components/up_sales_bottom_button.dart';
-import 'package:comwell_key_app/up_sales/cubit/up_sales_cubit.dart';
-import 'package:comwell_key_app/up_sales/cubit/up_sales_state.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_cubit.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_state.dart';
+import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
+import 'package:comwell_key_app/up_sales/models/room_upgrade_extra.dart';
+import 'package:comwell_key_app/up_sales/models/room_upgrade_list.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 PreregUpSalesCatalogPage extends StatelessWidget {
const PreregUpSalesCatalogPage({super.key});
@@ -14,71 +20,383 @@ class PreregUpSalesCatalogPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- return BlocBuilder<UpSalesCubit, UpSalesState>(builder: (context, state) {
- final cubit = context.read<UpSalesCubit>();
+ return BlocBuilder<PreregistrationCubit, PreregistrationState>(
+ builder: (context, state) {
+ final cubit = context.read<PreregistrationCubit>();
if (state.isLoading) {
return const Center(
- child: CircularProgressIndicator(),
- );
+ child: CircularProgressIndicator(),
+ );
}
- return SingleChildScrollView(
- child: Padding(
- padding: const EdgeInsets.only(
- top: 24,
- bottom: 100,
- left: 0,
- right: 0,
+ return SingleChildScrollView(
+ child: Padding(
+ padding: const EdgeInsets.only(
+ top: 24,
+ bottom: 100,
+ left: 0,
+ right: 0,
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: Text('up_sales_catalog_title'.tr(),
+ style: theme.textTheme.headlineLarge),
+ ),
+ const SizedBox(height: 40),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: Text('services'.tr(),
+ style: theme.textTheme.headlineMedium),
+ ),
+ const SizedBox(height: 8),
+ ServiceCatalog(
+ upSales: state.upSales,
+ selectedUpSales: state.selectedUpSales,
+ onTap: (roomUpgrade) {
+ final isSelected =
+ state.selectedUpSales.contains(roomUpgrade);
+ if (isSelected) {
+ cubit.removeUpgrade(roomUpgrade);
+ } else {
+ cubit.addSelected(roomUpgrade);
+ }
+ }),
+ const SizedBox(height: 24),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: Text('room_upgrades'.tr(),
+ style: theme.textTheme.headlineMedium),
+ ),
+ const SizedBox(height: 8),
+ RoomUpgradeCatalog(
+ upSales: state.upSales,
+ selectedUpSales: state.selectedUpSales,
+ onTap: (roomUpgrade) {
+ handleReadMoreTapPrereg(
+ context: context,
+ routeName: AppRoutes.roomUpgrade.name,
+ cubit: cubit,
+ roomUpgrade: roomUpgrade,
+ quantity: state.selectedUpSales.where((e) => e.id == roomUpgrade.id).length,
+ selectedUpSales: state.selectedUpSales,
+ );
+ },
+ onReadMoreTap: (context, roomUpgrade, quantity, selectedUpSales) =>
+ handleReadMoreTapPrereg(
+ context: context,
+ routeName: AppRoutes.roomUpgrade.name,
+ cubit: cubit,
+ roomUpgrade: roomUpgrade,
+ quantity: quantity,
+ selectedUpSales: selectedUpSales,
+ ),
+ ),
+ const SizedBox(height: 24),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: Text('other_up_sales'.tr(),
+ style: theme.textTheme.headlineMedium),
+ ),
+ const SizedBox(height: 8),
+ OtherUpgradeCatalog(
+ upSales: state.upSales,
+ selectedUpSales: state.selectedUpSales,
+ onTap: (roomUpgrade) {
+ final isSelected =
+ state.selectedUpSales.contains(roomUpgrade);
+ if (isSelected) {
+ cubit.removeUpgrade(roomUpgrade);
+ } else {
+ cubit.addSelected(roomUpgrade);
+ }
+ },
+ onReadMoreTap: (context, roomUpgrade, quantity, selectedUpSales) =>
+ handleReadMoreTapPrereg(
+ context: context,
+ routeName: AppRoutes.otherUpgrade.name,
+ cubit: cubit,
+ roomUpgrade: roomUpgrade,
+ quantity: cubit.extrasTotalQuantity(roomUpgrade),
+ selectedUpSales: selectedUpSales,
+ ),
+ ),
+ const SizedBox(height: 24),
+ ],
+ ),
+ ),
+ );
+ });
+ }
+
+ Widget _buildRoomUpgradeCatalog(
+ BuildContext context,
+ List<RoomUpgrade> upSales,
+ List<RoomUpgrade> selectedUpSales,
+ PreregistrationCubit cubit) {
+ final theme = Theme.of(context);
+ final roomUpSales = upSales
+ .where((roomUpgrade) => roomUpgrade.type == UpgradeType.room)
+ .toList();
+
+ if (roomUpSales.isEmpty) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: Text('no_room_upgrades_available'.tr(),
+ style: theme.textTheme.headlineMedium
+ ?.copyWith(color: colorHeadlineText)),
+ );
+ }
+
+ return SizedBox(
+ height: 289,
+ child: ListView.builder(
+ scrollDirection: Axis.horizontal,
+ itemCount: roomUpSales.length,
+ itemBuilder: (context, index) {
+ final roomUpgrade = roomUpSales.elementAt(index);
+ final isSelected = selectedUpSales.contains(roomUpgrade);
+
+ return Container(
+ width: 328,
+ height: 268,
+ margin:
+ const EdgeInsets.only(left: 16, right: 0, top: 8, bottom: 8),
+ padding: const EdgeInsets.all(12),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(12),
+ border: Border.all(color: colorDivider, width: 1),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: Text('up_sales_catalog_title'.tr(),
- style: theme.textTheme.headlineLarge),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(roomUpgrade.name,
+ style: theme.textTheme.headlineMedium),
+ ],
+ ),
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Row(
+ children: [
+ Text(
+ '${roomUpgrade.price} kr.',
+ style: theme.textTheme.headlineMedium,
+ ),
+ const SizedBox(width: 8),
+ GestureDetector(
+ onTap: () {
+ if (isSelected) {
+ cubit.removeUpgrade(roomUpgrade);
+ } else {
+ cubit.addSelected(roomUpgrade);
+ }
+ },
+ child: Container(
+ width: 20,
+ height: 20,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ border:
+ Border.all(color: colorDivider, width: 2),
+ color: isSelected
+ ? Colors.black
+ : Colors.transparent,
+ ),
+ child: isSelected
+ ? const Icon(Icons.check,
+ color: Colors.white, size: 12)
+ : null,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
),
- const SizedBox(height: 40),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: Text('services'.tr(),
- style: theme.textTheme.headlineMedium),
+ Text(
+ roomUpgrade.description,
+ style: theme.textTheme.bodySmall,
+ maxLines: 3,
+ overflow: TextOverflow.ellipsis,
),
- const SizedBox(height: 8),
- ServiceCatalog(
- upSales: cubit.upSales,
- selectedUpSales: cubit.state.selectedUpSales,
- onTap: (roomUpgrade) {
- final isSelected =
- cubit.state.selectedUpSales.contains(roomUpgrade);
- if (isSelected) {
- cubit.removeUpgrade(roomUpgrade);
- } else {
- cubit.addSelected(roomUpgrade);
- }
- }),
- const SizedBox(height: 24),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: Text('room_upgrades'.tr(),
- style: theme.textTheme.headlineMedium),
+ ],
+ ),
+ );
+ },
+ ),
+ );
+ }
+
+ Widget _buildOtherUpgradeCatalog(
+ BuildContext context,
+ List<RoomUpgrade> upSales,
+ List<RoomUpgrade> selectedUpSales,
+ PreregistrationCubit cubit) {
+ final theme = Theme.of(context);
+ final otherUpSales = upSales
+ .where((roomUpgrade) => roomUpgrade.type == UpgradeType.other)
+ .toList();
+
+ if (otherUpSales.isEmpty) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: Text('no_room_upgrades_available'.tr(),
+ style: theme.textTheme.headlineMedium
+ ?.copyWith(color: colorHeadlineText)),
+ );
+ }
+
+ return SizedBox(
+ height: 289,
+ child: ListView.builder(
+ scrollDirection: Axis.horizontal,
+ itemCount: otherUpSales.length,
+ itemBuilder: (context, index) {
+ final roomUpgrade = otherUpSales.elementAt(index);
+ final quantity = selectedUpSales
+ .where((element) => element.id == roomUpgrade.id)
+ .length;
+
+ return Container(
+ width: 328,
+ height: 268,
+ margin:
+ const EdgeInsets.only(left: 16, right: 0, top: 8, bottom: 8),
+ padding: const EdgeInsets.all(12),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(12),
+ border: Border.all(color: colorDivider, width: 1),
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(roomUpgrade.name,
+ style: theme.textTheme.headlineMedium),
+ ],
+ ),
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Row(
+ children: [
+ Text(
+ '${roomUpgrade.price} kr.',
+ style: theme.textTheme.headlineMedium,
+ ),
+ const SizedBox(width: 8),
+ Container(
+ width: 24,
+ height: 24,
+ decoration: BoxDecoration(
+ color: quantity > 0
+ ? Colors.black
+ : Colors.transparent,
+ shape: BoxShape.circle,
+ border:
+ Border.all(color: colorDivider, width: 1.5),
+ ),
+ child: quantity > 0
+ ? Center(
+ child: Text(quantity.toString(),
+ style: theme.textTheme.headlineSmall
+ ?.copyWith(
+ color: Colors.white,
+ fontSize: 11)),
+ )
+ : const SizedBox.shrink(),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ Text(
+ roomUpgrade.description,
+ style: theme.textTheme.bodySmall,
+ maxLines: 3,
+ overflow: TextOverflow.ellipsis,
),
- const SizedBox(height: 8),
- RoomUpgradeCatalog(cubit: cubit),
- const SizedBox(height: 24),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: Text('other_up_sales'.tr(),
- style: theme.textTheme.headlineMedium),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ IconButton(
+ onPressed: () {
+ if (quantity > 0) {
+ cubit.updateUpgradeQuantity(
+ roomUpgrade, quantity - 1);
+ }
+ },
+ icon: const Icon(Icons.remove),
+ ),
+ Text('$quantity'),
+ IconButton(
+ onPressed: () {
+ cubit.updateUpgradeQuantity(roomUpgrade, quantity + 1);
+ },
+ icon: const Icon(Icons.add),
+ ),
+ ],
),
- const SizedBox(height: 8),
- OtherUpgradeCatalog(cubit: cubit),
- const SizedBox(height: 24),
],
- ),
- ),
- );
- });
+ ),
+ );
+ },
+ ),
+ );
+ }
+
+ Future<void> handleReadMoreTapPrereg({
+ required BuildContext context,
+ required String routeName,
+ required dynamic cubit,
+ required RoomUpgrade roomUpgrade,
+ required int quantity,
+ required List<RoomUpgrade> selectedUpSales,
+ }) async {
+ final dynamic extra;
+ if (routeName == AppRoutes.otherUpgrade.name) {
+ extra = RoomUpgradeExtra(roomUpgrade: roomUpgrade, quantity: quantity);
+ } else if (routeName == AppRoutes.roomUpgrade.name) {
+ extra = RoomUpgradeList(roomUpgrade: roomUpgrade, roomUpgrades: selectedUpSales);
+ } else {
+ extra = null;
+ }
+ final roomUpgradeResponse = await context.pushNamed(routeName, extra: extra);
+ if (roomUpgradeResponse is List) {
+ if (roomUpgradeResponse[1] as bool) {
+ cubit.removeUpgrade(roomUpgradeResponse[0] as RoomUpgrade);
+ } else {
+ cubit.addSelected(roomUpgradeResponse[0] as RoomUpgrade);
+ }
+ }
+ if (roomUpgradeResponse is int) {
+ cubit.updateUpgradeQuantity(roomUpgrade, roomUpgradeResponse);
+ }
}
}
diff --git a/comwell_key_app/lib/pregistration/preregistration_flow.dart b/comwell_key_app/lib/pregistration/preregistration_flow.dart
index 18b082fd..43e6edc4 100644
--- a/comwell_key_app/lib/pregistration/preregistration_flow.dart
+++ b/comwell_key_app/lib/pregistration/preregistration_flow.dart
@@ -1,7 +1,7 @@
import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
-import 'package:comwell_key_app/pregistration/bloc/preregistration_state.dart';
-import 'package:comwell_key_app/pregistration/bloc/preregistration_cubit.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_state.dart';
+import 'package:comwell_key_app/pregistration/cubit/preregistration_cubit.dart';
import 'package:comwell_key_app/pregistration/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -27,25 +27,22 @@ class _PreregistrationFlowState extends State<PreregistrationFlow> {
return Scaffold(
backgroundColor: Colors.white,
appBar: const ComwellAppBar(),
- body: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 12.0),
- child: Builder(
- builder: (context) {
- if (state.loading) {
- return const Center(child: CircularProgressIndicator());
- }
- return PageView(
- key: const PageStorageKey("prereg_flow"),
- physics: const NeverScrollableScrollPhysics(),
- controller: cubit.pageController,
- children:
- PreregistrationPage.getPages(ValueKey(state)).toList(),
- );
- },
- ),
+ body: Builder(
+ builder: (context) {
+ if (state.isLoading) {
+ return const Center(child: CircularProgressIndicator());
+ }
+ return PageView(
+ key: const PageStorageKey("prereg_flow"),
+ physics: const NeverScrollableScrollPhysics(),
+ controller: cubit.pageController,
+ children:
+ PreregistrationPage.getPages(ValueKey(state)).toList(),
+ );
+ },
),
bottomNavigationBar: Builder(builder: (context) {
- if (state.loading) return const SizedBox();
+ if (state.isLoading) return const SizedBox();
return Column(
// BOTTOM NAVIGATION
mainAxisSize: MainAxisSize.min,
diff --git a/comwell_key_app/lib/pregistration/utils/utils.dart b/comwell_key_app/lib/pregistration/utils/utils.dart
index d754af68..f231b556 100644
--- a/comwell_key_app/lib/pregistration/utils/utils.dart
+++ b/comwell_key_app/lib/pregistration/utils/utils.dart
@@ -1,15 +1,17 @@
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/pages/prereg_address_page.dart';
import 'package:comwell_key_app/pregistration/pages/prereg_confirmation_page.dart';
import 'package:comwell_key_app/pregistration/pages/prereg_profile_page.dart';
import 'package:comwell_key_app/pregistration/pages/prereg_up_sales_catalog_page.dart';
import 'package:comwell_key_app/up_sales/cubit/up_sales_cubit.dart';
-import 'package:comwell_key_app/up_sales/up_sale_repository.dart';
+import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
import 'package:comwell_key_app/up_sales/up_sales_catalog.dart';
import 'package:comwell_key_app/utils/locator.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:path/path.dart';
enum PreregistrationPage {
profile,
@@ -34,9 +36,7 @@ enum PreregistrationPage {
create: (context) => PaymentCardsCubit(),
child: const PaymentCardsPage());
case PreregistrationPage.upSales:
- return BlocProvider(
- create: (context) => UpSalesCubit(upSaleRepository: locator<UpSaleRepository>())..init(),
- child: const PreregUpSalesCatalogPage());
+ return const PreregUpSalesCatalogPage();
case PreregistrationPage.confirmation:
return PreregConfirmationPage(key: key);
}
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index c8812fd6..b8f0c8d2 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -54,7 +54,7 @@ import 'package:comwell_key_app/up_sales/models/room_upgrade_extra.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade_list.dart';
import 'package:comwell_key_app/up_sales/pages/other_upgrade_page.dart';
import 'package:comwell_key_app/up_sales/pages/room_upgrade_page.dart';
-import 'package:comwell_key_app/up_sales/up_sale_repository.dart';
+import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
import 'package:comwell_key_app/up_sales/up_sales_catalog.dart';
import 'package:comwell_key_app/utils/stream_to_listenable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -287,7 +287,7 @@ GoRouter goRouter() {
bookingDetailsRepository:
locator<BookingDetailsRepository>(),
profileRepository: locator<ProfileRepository>(),
- upSaleRepository: locator<UpSaleRepository>()),
+ upSaleRepository: locator<UpSalesRepository>()),
child: const BookingDetailsPage(),
);
},
@@ -390,7 +390,7 @@ GoRouter goRouter() {
builder: (context, state) {
return BlocProvider(
create: (context) =>
- UpSalesCubit(upSaleRepository: locator<UpSaleRepository>())
+ UpSalesCubit(upSaleRepository: locator<UpSalesRepository>())
..init(),
child: const UpSalesCatalog(),
);
@@ -403,7 +403,7 @@ GoRouter goRouter() {
final roomUpgradeList = state.extra as RoomUpgradeList;
return BlocProvider(
create: (context) =>
- UpSalesCubit(upSaleRepository: locator<UpSaleRepository>())..init(),
+ UpSalesCubit(upSaleRepository: locator<UpSalesRepository>())..init(),
child: RoomUpgradePage(roomUpgradeList: roomUpgradeList),
);
},
@@ -415,7 +415,7 @@ GoRouter goRouter() {
final roomUpgrade = state.extra as RoomUpgradeExtra;
return BlocProvider(
create: (context) =>
- UpSalesCubit.withExtra(upSaleRepository: locator<UpSaleRepository>(), extra: roomUpgrade),
+ UpSalesCubit.withExtra(upSaleRepository: locator<UpSalesRepository>(), extra: roomUpgrade),
child: OtherUpgradePage(extra: roomUpgrade),
);
}),
diff --git a/comwell_key_app/lib/up_sales/components/catalog/other_upgrade_catalog.dart b/comwell_key_app/lib/up_sales/components/catalog/other_upgrade_catalog.dart
index 30c309aa..a9beef88 100644
--- a/comwell_key_app/lib/up_sales/components/catalog/other_upgrade_catalog.dart
+++ b/comwell_key_app/lib/up_sales/components/catalog/other_upgrade_catalog.dart
@@ -7,13 +7,16 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
class OtherUpgradeCatalog extends StatelessWidget {
- final UpSalesCubit cubit;
- const OtherUpgradeCatalog({super.key, required this.cubit});
+ final List<RoomUpgrade> upSales;
+ final List<RoomUpgrade> selectedUpSales;
+ final Function(RoomUpgrade) onTap;
+ final Future<void> Function(BuildContext context, RoomUpgrade roomUpgrade, int quantity, List<RoomUpgrade> selectedUpSales) onReadMoreTap;
+ const OtherUpgradeCatalog({super.key, required this.upSales, required this.selectedUpSales, required this.onTap, required this.onReadMoreTap});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- final otherUpSales = cubit.upSales
+ final otherUpSales = upSales
.where((roomUpgrade) => roomUpgrade.type == UpgradeType.other)
.toList();
@@ -35,9 +38,13 @@ class OtherUpgradeCatalog extends StatelessWidget {
width: 328,
height: 268,
roomUpgrade: otherUpSales.elementAt(index),
- isSelected: cubit.state.selected,
+ isSelected: selectedUpSales.contains(otherUpSales.elementAt(index)),
routeName: AppRoutes.otherUpgrade.name,
showCounter: true,
+ selectedUpSales: selectedUpSales,
+ onTap: onTap,
+ onReadMoreTap: (context, roomUpgrade, quantity, selectedUpSales) =>
+ onReadMoreTap(context, roomUpgrade, quantity, selectedUpSales),
);
},
),
diff --git a/comwell_key_app/lib/up_sales/components/catalog/room_uprade_catalog.dart b/comwell_key_app/lib/up_sales/components/catalog/room_uprade_catalog.dart
index 461b651d..76557655 100644
--- a/comwell_key_app/lib/up_sales/components/catalog/room_uprade_catalog.dart
+++ b/comwell_key_app/lib/up_sales/components/catalog/room_uprade_catalog.dart
@@ -7,13 +7,16 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
class RoomUpgradeCatalog extends StatelessWidget {
- final UpSalesCubit cubit;
- const RoomUpgradeCatalog({super.key, required this.cubit});
+ final List<RoomUpgrade> upSales;
+ final List<RoomUpgrade> selectedUpSales;
+ final Function(RoomUpgrade) onTap;
+ final Future<void> Function(BuildContext context, RoomUpgrade roomUpgrade, int quantity, List<RoomUpgrade> selectedUpSales) onReadMoreTap;
+ const RoomUpgradeCatalog({super.key, required this.upSales, required this.selectedUpSales, required this.onTap, required this.onReadMoreTap});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- final roomUpSales = cubit.upSales
+ final roomUpSales = upSales
.where((roomUpgrade) => roomUpgrade.type == UpgradeType.room)
.toList();
@@ -35,9 +38,13 @@ class RoomUpgradeCatalog extends StatelessWidget {
width: 328,
height: 268,
roomUpgrade: roomUpSales.elementAt(index),
- isSelected: cubit.state.selected,
+ isSelected: selectedUpSales.contains(roomUpSales.elementAt(index)),
routeName: AppRoutes.roomUpgrade.name,
showCounter: false,
+ selectedUpSales: selectedUpSales,
+ onTap: onTap,
+ onReadMoreTap: (context, roomUpgrade, quantity, selectedUpSales) =>
+ onReadMoreTap(context, roomUpgrade, quantity, selectedUpSales),
);
},
),
diff --git a/comwell_key_app/lib/up_sales/components/comwell_radio_button.dart b/comwell_key_app/lib/up_sales/components/comwell_radio_button.dart
index 23f56a9d..a6c9d04b 100644
--- a/comwell_key_app/lib/up_sales/components/comwell_radio_button.dart
+++ b/comwell_key_app/lib/up_sales/components/comwell_radio_button.dart
@@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
class ComwellRadioButton extends StatelessWidget {
final bool selected;
- final Function() onTap;
- const ComwellRadioButton({super.key, required this.selected, required this.onTap});
+ final Function()? onTap;
+ const ComwellRadioButton({super.key, required this.selected, this.onTap});
@override
Widget build(BuildContext context) {
diff --git a/comwell_key_app/lib/up_sales/components/confirm_up_sales_dialog.dart b/comwell_key_app/lib/up_sales/components/confirm_up_sales_dialog.dart
new file mode 100644
index 00000000..3e4274c4
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/components/confirm_up_sales_dialog.dart
@@ -0,0 +1,79 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/up_sales/cubit/up_sales_cubit.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+class ConfirmUpSalesDialog extends StatelessWidget {
+ final VoidCallback onContinue;
+ final int extrasTotalPrice;
+ const ConfirmUpSalesDialog({super.key, required this.onContinue, required this.extrasTotalPrice});
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+
+ return Dialog(
+ backgroundColor: Colors.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(20),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.all(24.0),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ "confirm_up_sales_dialog_title".tr(),
+ textAlign: TextAlign.center,
+ style: theme.textTheme.headlineMedium?.copyWith(
+ color: colorHeadlineText,
+ ),
+ ),
+ Text(
+ "confirm_up_sales_dialog_subtitle".tr(args: [extrasTotalPrice.toString()]),
+ textAlign: TextAlign.center,
+ style: theme.textTheme.bodyMedium
+ ),
+ const SizedBox(height: 24),
+ SizedBox(
+ width: double.infinity,
+ child: ElevatedButton(
+ style: theme.elevatedButtonTheme.style?.copyWith(
+ padding: const WidgetStatePropertyAll(
+ EdgeInsets.symmetric(vertical: 16)),
+ ),
+ onPressed: () {
+ onContinue();
+ Navigator.of(context).pop();
+ },
+ child: Text(
+ "confirm_up_sales_dialog_confirm".tr(),
+ style: theme.textTheme.bodyMedium?.copyWith(
+ color: Colors.white,
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(height: 12),
+ SizedBox(
+ width: double.infinity,
+ child: OutlinedButton(
+ style: OutlinedButton.styleFrom(
+ side: BorderSide(color: Colors.grey[400]!),
+ padding: const EdgeInsets.symmetric(vertical: 16),
+ ),
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ child: Text(
+ "cancel".tr(),
+ style: theme.textTheme.bodyMedium
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/up_sales/components/up_sales_bottom_button.dart b/comwell_key_app/lib/up_sales/components/up_sales_bottom_button.dart
index 392eb4a9..17412509 100644
--- a/comwell_key_app/lib/up_sales/components/up_sales_bottom_button.dart
+++ b/comwell_key_app/lib/up_sales/components/up_sales_bottom_button.dart
@@ -1,20 +1,29 @@
+import 'package:comwell_key_app/common/components/generic_dialog.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/up_sales/components/confirm_up_sales_dialog.dart';
+import 'package:comwell_key_app/up_sales/cubit/up_sales_cubit.dart';
+import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
class UpSalesBottomButton extends StatelessWidget {
final List<Widget> children;
- final VoidCallback? onContinue;
-
+ final VoidCallback onContinue;
+ final VoidCallback? onAddUpSale;
+ final List<RoomUpgrade> selectedUpSales;
+ final int extrasTotalPrice;
const UpSalesBottomButton({
super.key,
- this.onContinue,
+ required this.onContinue,
required this.children,
+ required this.selectedUpSales,
+ required this.extrasTotalPrice,
+ this.onAddUpSale,
});
@override
Widget build(BuildContext context) {
- final theme = Theme.of(context);
return Container(
color: Colors.white,
child: Padding(
@@ -25,14 +34,20 @@ class UpSalesBottomButton extends StatelessWidget {
bottom: 40,
),
child: ElevatedButton(
- onPressed: onContinue,
+ onPressed: () {
+ if (onAddUpSale != null) {
+ onContinue();
+ }
+ if (selectedUpSales.isNotEmpty) {
+ showDialog<void>(
+ context: context,
+ builder: (context) => ConfirmUpSalesDialog(onContinue: onContinue, extrasTotalPrice: extrasTotalPrice),
+ );
+ }
+ },
style: ButtonStyle(
elevation: WidgetStateProperty.all(0),
- backgroundColor: WidgetStateProperty.resolveWith((states) {
-
-
- return sandColor[80];
- }),
+ backgroundColor: WidgetStateProperty.all(sandColor[80]),
foregroundColor: const WidgetStatePropertyAll(Colors.white),
),
child: Padding(
diff --git a/comwell_key_app/lib/up_sales/components/up_sales_upgrades_widget.dart b/comwell_key_app/lib/up_sales/components/up_sales_upgrades_widget.dart
index 8263f63b..89fecc27 100644
--- a/comwell_key_app/lib/up_sales/components/up_sales_upgrades_widget.dart
+++ b/comwell_key_app/lib/up_sales/components/up_sales_upgrades_widget.dart
@@ -6,12 +6,10 @@ import 'package:comwell_key_app/up_sales/cubit/up_sales_state.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade_extra.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade_list.dart';
-import 'package:comwell_key_app/up_sales/up_sale_repository.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:go_router/go_router.dart';
class UpSalesUpgradesWidget extends StatelessWidget {
final double width;
@@ -19,7 +17,11 @@ class UpSalesUpgradesWidget extends StatelessWidget {
final RoomUpgrade roomUpgrade;
final bool isSelected;
final String routeName;
- final bool showCounter;
+ final bool showCounter;
+ final Function(RoomUpgrade) onTap;
+ final Future<void> Function(BuildContext context, RoomUpgrade roomUpgrade,
+ int quantity, List<RoomUpgrade> selectedUpSales) onReadMoreTap;
+ final List<RoomUpgrade> selectedUpSales;
const UpSalesUpgradesWidget(
{super.key,
this.width = 328,
@@ -27,150 +29,124 @@ class UpSalesUpgradesWidget extends StatelessWidget {
required this.roomUpgrade,
this.isSelected = false,
required this.routeName,
- this.showCounter = false});
+ this.showCounter = false,
+ required this.onTap,
+ required this.selectedUpSales,
+ required this.onReadMoreTap});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- final cubit = context.read<UpSalesCubit>();
-
- return BlocBuilder<UpSalesCubit, UpSalesState>(builder: (context, state) {
- final isSelected = state.selectedUpSales.contains(roomUpgrade);
- final quantity = state.selectedUpSales
+ final quantity = selectedUpSales
.where((element) => element.id == roomUpgrade.id)
.length;
- return Container(
- width: width,
- height: height,
- margin: const EdgeInsets.only(left: 16, right: 8, top: 8, bottom: 16),
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(10),
- border: Border.all(color: colorDivider, width: 1),
- ),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Stack(
- children: [
- ClipRRect(
- borderRadius: const BorderRadius.only(
- topLeft: Radius.circular(10),
- topRight: Radius.circular(10),
- ),
- child: Image.asset(
- roomUpgrade.images!.first,
- height: 180,
- width: double.infinity,
- fit: BoxFit.cover,
- ),
+ return Container(
+ width: width,
+ height: height,
+ margin: const EdgeInsets.only(left: 16, right: 8, top: 8, bottom: 16),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(10),
+ border: Border.all(color: colorDivider, width: 1),
+ ),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Stack(
+ children: [
+ ClipRRect(
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(10),
+ topRight: Radius.circular(10),
),
- if (roomUpgrade.tags.firstOrNull != null)
- Positioned(
- top: 16,
- right: 16,
- child: Container(
- padding: const EdgeInsets.symmetric(
- horizontal: 12, vertical: 4),
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(32),
- ),
- child: Text(
- '${roomUpgrade.tags.first} m2',
- style: theme.textTheme.headlineMedium
- ?.copyWith(fontSize: 11),
- ),
+ child: Image.asset(
+ roomUpgrade.images!.first,
+ height: 180,
+ width: double.infinity,
+ fit: BoxFit.cover,
+ ),
+ ),
+ if (roomUpgrade.tags.firstOrNull != null)
+ Positioned(
+ top: 16,
+ right: 16,
+ child: Container(
+ padding:
+ const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(32),
+ ),
+ child: Text(
+ '${roomUpgrade.tags.first} m2',
+ style: theme.textTheme.headlineMedium
+ ?.copyWith(fontSize: 11),
),
),
- ],
- ),
- Padding(
- padding:
- const EdgeInsets.only(left: 8, right: 8, top: 16, bottom: 8),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Flexible(
- child: Text(
- roomUpgrade.name,
+ ),
+ ],
+ ),
+ Padding(
+ padding:
+ const EdgeInsets.only(left: 8, right: 8, top: 16, bottom: 8),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Flexible(
+ child: Text(
+ roomUpgrade.name,
+ style: theme.textTheme.headlineMedium,
+ maxLines: 1,
+ overflow: TextOverflow.visible,
+ ),
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ '${roomUpgrade.price} kr.',
style: theme.textTheme.headlineMedium,
- maxLines: 1,
- overflow: TextOverflow.visible,
),
- ),
- Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text(
- '${roomUpgrade.price} kr.',
- style: theme.textTheme.headlineMedium,
- ),
- const SizedBox(width: 8),
- showCounter
- ? UpgradesCounter(quantity: quantity)
- : ComwellRadioButton(
- selected: isSelected, onTap: () {}),
- ],
- ),
- ],
- ),
- const SizedBox(height: 8),
- GestureDetector(
- onTap: () async {
- final dynamic extra;
- if (routeName == AppRoutes.otherUpgrade.name) {
- extra = RoomUpgradeExtra(
- roomUpgrade: roomUpgrade, quantity: quantity);
- } else if (routeName ==
- AppRoutes.roomUpgrade.name) {
- extra = RoomUpgradeList(roomUpgrade: roomUpgrade, roomUpgrades: state.selectedUpSales);
- } else {
- extra = null;
- }
-
- final roomUpgradeResponse = await context
- .pushNamed(routeName, extra: extra);
-
- if (roomUpgradeResponse is List) {
- if (roomUpgradeResponse[1] as bool) {
- cubit.removeUpgrade(roomUpgradeResponse[0] as RoomUpgrade);
- } else {
- cubit.addSelected(roomUpgradeResponse[0] as RoomUpgrade);
- }
- }
-
- if (roomUpgradeResponse is int) {
- cubit.updateUpgradeQuantity(
- roomUpgrade, roomUpgradeResponse);
- }
- },
- child: Text(
- 'read_more_up_sales'.tr(),
- style: theme.textTheme.bodySmall?.copyWith(
- color: sandColor[80],
- decoration: TextDecoration.underline,
- decorationColor: sandColor[80],
- ),
+ const SizedBox(width: 8),
+ showCounter
+ ? UpgradesCounter(quantity: quantity)
+ : ComwellRadioButton(
+ selected: isSelected),
+ ],
+ ),
+ ],
+ ),
+ const SizedBox(height: 8),
+ GestureDetector(
+ onTap: () {
+ onReadMoreTap(
+ context, roomUpgrade, quantity, selectedUpSales);
+ },
+ child: Text(
+ 'read_more_up_sales'.tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: sandColor[80],
+ decoration: TextDecoration.underline,
+ decorationColor: sandColor[80],
),
),
- ],
- ),
+ ),
+ ],
),
- ],
- ),
+ ),
+ ],
),
- ],
- ),
- );
- });
+ ),
+ ],
+ ),
+ );
}
}
diff --git a/comwell_key_app/lib/up_sales/cubit/up_sales_cubit.dart b/comwell_key_app/lib/up_sales/cubit/up_sales_cubit.dart
index fc73e9e3..82db47f6 100644
--- a/comwell_key_app/lib/up_sales/cubit/up_sales_cubit.dart
+++ b/comwell_key_app/lib/up_sales/cubit/up_sales_cubit.dart
@@ -4,10 +4,10 @@ import 'package:comwell_key_app/up_sales/models/dto/room_upgrade_dto.dart';
import 'package:comwell_key_app/up_sales/models/room_facility.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade_extra.dart';
-import 'package:comwell_key_app/up_sales/up_sale_repository.dart';
+import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
class UpSalesCubit extends Cubit<UpSalesState> {
- final UpSaleRepository upSaleRepository;
+ final UpSalesRepository upSaleRepository;
List<RoomUpgrade> upSales = [];
late RoomUpgradeExtra extra;
@@ -26,16 +26,15 @@ class UpSalesCubit extends Cubit<UpSalesState> {
emit(UpSalesState(
selected: false,
upSales: upSales,
- selectedUpSales: [],
+ selectedUpSales: const [],
isLoading: true,
error: null));
try {
upSales = await upSaleRepository.getMockUpSales();
- print("upSales: ${upSales.length}");
emit(state.loaded(upSales: upSales));
} catch (e) {
- emit(state.setupError(error: Error()));
+ emit(state.setupError(error: Exception(e)));
}
}
@@ -59,12 +58,13 @@ class UpSalesCubit extends Cubit<UpSalesState> {
}
void decrement() {
- if (extra.quantity > 0 && state.quantity > 0) {
+ if (extra.quantity > 0 || state.quantity > 0) {
emit(state.removeQuantity());
}
}
void onContinue() {
+
emit(state.copyWith(selected: false));
}
@@ -87,4 +87,14 @@ class UpSalesCubit extends Cubit<UpSalesState> {
emit(state.removeSelectedUpSales(roomUpgrade: roomUpgrade));
print("length: ${state.selectedUpSales.length}");
}
+
+ int get extrasTotalPrice {
+ return state.selectedUpSales.fold(0, (sum, upgrade) => sum + int.parse(upgrade.price));
+ }
+
+ int extrasTotalQuantity(RoomUpgrade roomUpgrade) {
+ return state.selectedUpSales
+ .where((element) => element.id == roomUpgrade.id)
+ .length;
+ }
}
diff --git a/comwell_key_app/lib/up_sales/cubit/up_sales_state.dart b/comwell_key_app/lib/up_sales/cubit/up_sales_state.dart
index 08e675c9..b71bcd09 100644
--- a/comwell_key_app/lib/up_sales/cubit/up_sales_state.dart
+++ b/comwell_key_app/lib/up_sales/cubit/up_sales_state.dart
@@ -5,7 +5,7 @@ class UpSalesState extends Equatable {
final bool selected;
final List<RoomUpgrade> upSales;
final List<RoomUpgrade> selectedUpSales;
- final Error? error;
+ final Exception? error;
final bool isLoading;
final int quantity;
const UpSalesState(
@@ -26,10 +26,10 @@ class UpSalesState extends Equatable {
error = null,
isLoading = false;
- UpSalesState setupError({required Error error}) =>
+ UpSalesState setupError({required Exception error}) =>
copyWith(isLoading: false, error: error);
- UpSalesState loading() => copyWith(isLoading: true);
+ UpSalesState preRegLoading() => copyWith(isLoading: true);
UpSalesState loaded({required List<RoomUpgrade> upSales}) =>
copyWith(isLoading: false, upSales: upSales);
@@ -68,7 +68,7 @@ class UpSalesState extends Equatable {
List<RoomUpgrade>? upSales,
List<RoomUpgrade>? selectedUpSales,
bool? isLoading,
- Error? error,
+ Exception? error,
int? quantity,
}) {
return UpSalesState(
diff --git a/comwell_key_app/lib/up_sales/pages/other_upgrade_page.dart b/comwell_key_app/lib/up_sales/pages/other_upgrade_page.dart
index 3bb28259..32c53b62 100644
--- a/comwell_key_app/lib/up_sales/pages/other_upgrade_page.dart
+++ b/comwell_key_app/lib/up_sales/pages/other_upgrade_page.dart
@@ -108,9 +108,14 @@ class _OtherUpgradePageState extends State<OtherUpgradePage> {
Expanded(
flex: 2,
child: UpSalesBottomButton(
+ onAddUpSale: () {
+ Navigator.pop(context, [widget.extra.roomUpgrade, true]);
+ },
onContinue: () {
Navigator.pop(context, cubit.state.quantity);
},
+ selectedUpSales: cubit.state.selectedUpSales,
+ extrasTotalPrice: cubit.extrasTotalPrice,
children: [Text('add_to_booking'.tr())],
),
),
diff --git a/comwell_key_app/lib/up_sales/pages/room_upgrade_page.dart b/comwell_key_app/lib/up_sales/pages/room_upgrade_page.dart
index f03cdb38..04554266 100644
--- a/comwell_key_app/lib/up_sales/pages/room_upgrade_page.dart
+++ b/comwell_key_app/lib/up_sales/pages/room_upgrade_page.dart
@@ -34,7 +34,7 @@ class _RoomUpgradePageState extends State<RoomUpgradePage> {
final isSelected = widget.roomUpgradeList.roomUpgrades.contains(widget.roomUpgradeList.roomUpgrade);
return BlocBuilder<UpSalesCubit, UpSalesState>(builder: (context, state) {
-
+ final cubit = context.read<UpSalesCubit>();
return Scaffold(
extendBodyBehindAppBar: true,
appBar: const ComwellAppBar(),
@@ -144,9 +144,14 @@ class _RoomUpgradePageState extends State<RoomUpgradePage> {
children: [
const Divider(color: colorDivider),
UpSalesBottomButton(
+ onAddUpSale: () {
+ Navigator.pop(context, [widget.roomUpgradeList.roomUpgrade, isSelected]);
+ },
onContinue: () {
Navigator.pop(context, [widget.roomUpgradeList.roomUpgrade, isSelected]);
},
+ selectedUpSales: state.selectedUpSales,
+ extrasTotalPrice: cubit.extrasTotalPrice,
children: [
isSelected
? Text(
diff --git a/comwell_key_app/lib/up_sales/up_sale_repository.dart b/comwell_key_app/lib/up_sales/up_sale_repository.dart
deleted file mode 100644
index aba631d2..00000000
--- a/comwell_key_app/lib/up_sales/up_sale_repository.dart
+++ /dev/null
@@ -1,372 +0,0 @@
-import 'package:comwell_key_app/services/api.dart';
-import 'package:comwell_key_app/up_sales/mappers/room_upgrade_mapper.dart';
-import 'package:comwell_key_app/up_sales/models/dto/room_upgrade_dto.dart';
-import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
-import 'package:comwell_key_app/utils/json.dart';
-import 'package:comwell_key_app/up_sales/models/dto/room_facility_dto.dart';
-
-class UpSaleRepository {
- final Api api = Api();
-
- UpSaleRepository();
-
- Future<Json> getUpSales() async {
- final response = await api.fetchUpSales();
- return response;
- }
-
- Future<List<RoomUpgrade>> getMockUpSales() async {
- return mockRoomUpgrades.toRoomUpgrades();
- }
-}
-
-// Mock data for RoomUpgrade and RoomFacility
-final List<RoomUpgradeDTO> mockRoomUpgrades = [
- RoomUpgradeDTO(
- name: 'Standard Double Room',
- price: '1200',
- images: ['assets/images/welcome_image.jpeg', 'assets/images/current_room.png', 'assets/images/no_current_bookings_background.jpeg'],
- description:
- 'A cozy room with a double bed, perfect for couples or solo travelers seeking comfort and convenience. A cozy room with a double bed, perfect for couples or solo travelers seeking comfort and convenience. A cozy room with a double bed, perfect for couples or solo travelers seeking comfort and convenience.',
- id: '1',
- tags: ['20'],
- type: 'room',
- facilities: [
- RoomFacilityDTO(
- name: '1x enkelseng',
- icon: 'assets/icons/ic_single_bed.svg',
- facilityType: 'Bed'),
- RoomFacilityDTO(
- name: '1x dobbelseng',
- icon: 'assets/icons/ic_double_bed.svg',
- facilityType: 'Bed'),
- RoomFacilityDTO(
- name: 'TV',
- icon: 'assets/icons/ic_tv.svg',
- facilityType: 'Electronics'),
- RoomFacilityDTO(
- name: 'Gratis WiFi',
- icon: 'assets/icons/ic_wifi.svg',
- facilityType: 'Electronics'),
- RoomFacilityDTO(
- name: 'Hårtørrer',
- icon: 'assets/icons/ic_hairdryer.svg',
- facilityType: 'Bathroom'),
- RoomFacilityDTO(
- name: 'Arbejdsplads',
- icon: 'assets/icons/ic_desk.svg',
- facilityType: 'Business'),
- RoomFacilityDTO(
- name: 'Roomservice',
- icon: 'assets/icons/ic_service_bowl.svg',
- facilityType: 'Service'),
- RoomFacilityDTO(
- name: 'Strygejern & -bræt',
- icon: 'assets/icons/ic_iron.svg',
- facilityType: 'Room'),
- RoomFacilityDTO(
- name: 'Minibar',
- icon: 'assets/icons/ic_minibar.svg',
- facilityType: 'Room'),
- ],
- ),
- RoomUpgradeDTO(
- name: 'Junior Suite',
- price: '1800',
- images: ['assets/images/no_current_bookings_background.jpeg'],
- description:
- 'Spacious Junior Suite with a separate living area, ideal for guests who appreciate extra space and luxury. Spacious Junior Suite with a separate living area, ideal for guests who appreciate extra space and luxury. Spacious Junior Suite with a separate living area, ideal for guests who appreciate extra space and luxury.',
- id: '2',
- tags: ['35'],
- type: 'room',
- facilities: [
- RoomFacilityDTO(
- name: '1x enkelseng',
- icon: 'assets/icons/ic_single_bed.svg',
- facilityType: 'Bed'),
- RoomFacilityDTO(
- name: '2x dobbelseng',
- icon: 'assets/icons/ic_double_bed.svg',
- facilityType: 'Bed'),
- RoomFacilityDTO(
- name: 'TV',
- icon: 'assets/icons/ic_tv.svg',
- facilityType: 'Electronics'),
- RoomFacilityDTO(
- name: 'Gratis WiFi',
- icon: 'assets/icons/ic_wifi.svg',
- facilityType: 'Electronics'),
- RoomFacilityDTO(
- name: 'Hårtørrer',
- icon: 'assets/icons/ic_hairdryer.svg',
- facilityType: 'Bathroom'),
- RoomFacilityDTO(
- name: 'Badekar',
- icon: 'assets/icons/ic_bathtub.svg',
- facilityType: 'Bathroom'),
- RoomFacilityDTO(
- name: 'Arbejdsplads',
- icon: 'assets/icons/ic_desk.svg',
- facilityType: 'Business'),
- RoomFacilityDTO(
- name: 'Roomservice',
- icon: 'assets/icons/ic_service_bowl.svg',
- facilityType: 'Service'),
- RoomFacilityDTO(
- name: 'Strygejern & -bræt',
- icon: 'assets/icons/ic_iron.svg',
- facilityType: 'Room'),
- RoomFacilityDTO(
- name: 'Terrasse',
- icon: 'assets/icons/ic_balcony.svg',
- facilityType: 'Room'),
- RoomFacilityDTO(
- name: 'Te-køkken',
- icon: 'assets/icons/ic_kettle.svg',
- facilityType: 'Room'),
- RoomFacilityDTO(
- name: 'Stue',
- icon: 'assets/icons/ic_leather_chair.svg',
- facilityType: 'Room'),
- RoomFacilityDTO(
- name: 'Minibar',
- icon: 'assets/icons/ic_minibar.svg',
- facilityType: 'Room'),
- ],
- ),
- RoomUpgradeDTO(
- name: 'Suite',
- price: '2500',
- images: ['assets/images/current_room.png'],
- description:
- 'Our most luxurious suite, featuring a large living room, private terrace, and premium amenities for a memorable stay. Our most luxurious suite, featuring a large living room, private terrace, and premium amenities for a memorable stay. Our most luxurious suite, featuring a large living room, private terrace, and premium amenities for a memorable stay.',
- id: '3',
- tags: ['50'],
- type: 'room',
- facilities: [
- RoomFacilityDTO(
- name: '1x enkelseng',
- icon: 'assets/icons/ic_single_bed.svg',
- facilityType: 'Bed'),
- RoomFacilityDTO(
- name: 'TV',
- icon: 'assets/icons/ic_tv.svg',
- facilityType: 'Electronics'),
- RoomFacilityDTO(
- name: 'Gratis WiFi',
- icon: 'assets/icons/ic_wifi.svg',
- facilityType: 'Electronics'),
- RoomFacilityDTO(
- name: 'Hårtørrer',
- icon: 'assets/icons/ic_hairdryer.svg',
- facilityType: 'Bathroom'),
- RoomFacilityDTO(
- name: 'Badekar',
- icon: 'assets/icons/ic_bathtub.svg',
- facilityType: 'Bathroom'),
- RoomFacilityDTO(
- name: 'Arbejdsplads',
- icon: 'assets/icons/ic_desk.svg',
- facilityType: 'Business'),
- RoomFacilityDTO(
- name: 'Roomservice',
- icon: 'assets/icons/ic_service_bowl.svg',
- facilityType: 'Service'),
- RoomFacilityDTO(
- name: 'Strygejern & -bræt',
- icon: 'assets/icons/ic_iron.svg',
- facilityType: 'Room'),
- RoomFacilityDTO(
- name: 'Terrasse',
- icon: 'assets/icons/ic_balcony.svg',
- facilityType: 'Room'),
- RoomFacilityDTO(
- name: 'Te-køkken',
- icon: 'assets/icons/ic_kettle.svg',
- facilityType: 'Room'),
- RoomFacilityDTO(
- name: 'Stue',
- icon: 'assets/icons/ic_leather_chair.svg',
- facilityType: 'Room'),
- RoomFacilityDTO(
- name: 'Minibar',
- icon: 'assets/icons/ic_minibar.svg',
- facilityType: 'Room'),
- ],
- ),
- RoomUpgradeDTO(
- name: 'Standard Double Plus Room',
- price: '1400',
- images: ['assets/images/login_screen_background.png'],
- description:
- 'An upgraded double room with extra amenities and a modern touch, perfect for a relaxing stay. An upgraded double room with extra amenities and a modern touch, perfect for a relaxing stay. An upgraded double room with extra amenities and a modern touch, perfect for a relaxing stay.',
- id: '4',
- tags: ['25'],
- type: 'room',
- facilities: [
- RoomFacilityDTO(
- name: '2x dobbelseng',
- icon: 'assets/icons/ic_double_bed.svg',
- facilityType: 'Bed'),
- RoomFacilityDTO(
- name: 'TV',
- icon: 'assets/icons/ic_tv.svg',
- facilityType: 'Electronics'),
- RoomFacilityDTO(
- name: 'Gratis WiFi',
- icon: 'assets/icons/ic_wifi.svg',
- facilityType: 'Electronics'),
- RoomFacilityDTO(
- name: 'Hårtørrer',
- icon: 'assets/icons/ic_hairdryer.svg',
- facilityType: 'Bathroom'),
- RoomFacilityDTO(
- name: 'Arbejdsplads',
- icon: 'assets/icons/ic_desk.svg',
- facilityType: 'Business'),
- RoomFacilityDTO(
- name: 'Roomservice',
- icon: 'assets/icons/ic_service_bowl.svg',
- facilityType: 'Service'),
- ],
- ),
- RoomUpgradeDTO(
- name: 'Standard Twin Plus Room',
- price: '1450',
- images: ['assets/images/login_screen_background.png'],
- description:
- 'A spacious twin room with two single beds and modern facilities, ideal for friends or colleagues traveling together. A spacious twin room with two single beds and modern facilities, ideal for friends or colleagues traveling together. A spacious twin room with two single beds and modern facilities, ideal for friends or colleagues traveling together.',
- id: '5',
- tags: ['27'],
- type: 'room',
- facilities: [
- RoomFacilityDTO(
- name: '2x dobbelseng',
- icon: 'assets/icons/ic_double_bed.svg',
- facilityType: 'Bed'),
- RoomFacilityDTO(
- name: 'TV',
- icon: 'assets/icons/ic_tv.svg',
- facilityType: 'Electronics'),
- RoomFacilityDTO(
- name: 'Gratis WiFi',
- icon: 'assets/icons/ic_wifi.svg',
- facilityType: 'Electronics'),
- RoomFacilityDTO(
- name: 'Hårtørrer',
- icon: 'assets/icons/ic_hairdryer.svg',
- facilityType: 'Bathroom'),
- RoomFacilityDTO(
- name: 'Arbejdsplads',
- icon: 'assets/icons/ic_desk.svg',
- facilityType: 'Business'),
- RoomFacilityDTO(
- name: 'Strygejern & -bræt',
- icon: 'assets/icons/ic_iron.svg',
- facilityType: 'Room'),
- RoomFacilityDTO(
- name: 'Minibar',
- icon: 'assets/icons/ic_minibar.svg',
- facilityType: 'Room'),
- ],
- ),
- RoomUpgradeDTO(
- name: 'Bottle of Champagne',
- price: '450',
- images: ['assets/images/catalog_image.png'],
- description:
- 'Celebrate your stay with a bottle of premium champagne and a selection of fine chocolates delivered to your room.',
- id: '6',
- tags: [],
- type: 'other',
- facilities: [],
- ),
- RoomUpgradeDTO(
- name: 'Luxury Flower Arrangement',
- price: '350',
- images: ['assets/images/login_screen_background.png'],
- description:
- 'A beautiful bouquet of fresh seasonal flowers to brighten up your room and create a welcoming atmosphere.',
- id: '7',
- tags: [],
- type: 'other',
- facilities: [],
- ),
- RoomUpgradeDTO(
- name: 'Romantic Evening Package',
- price: '750',
- images: ['assets/images/catalog_image.png'],
- description:
- 'Create a romantic atmosphere with rose petals, candles, champagne, and a special dessert for two.',
- id: '8',
- tags: [],
- type: 'other',
- facilities: [],
- ),
- RoomUpgradeDTO(
- name: 'Breakfast in Bed',
- price: '250',
- images: ['assets/images/login_screen_background.png'],
- description:
- 'Start your day in luxury with a full breakfast served in the comfort of your room.',
- id: '9',
- tags: [],
- type: 'other',
- facilities: [],
- ),
- RoomUpgradeDTO(
- name: 'Wellness Package',
- price: '600',
- images: ['assets/images/login_screen_background.png'],
- description:
- 'Indulge in a wellness experience with a selection of premium spa products, bath salts, and aromatherapy items.',
- id: '10',
- tags: [],
- type: 'other',
- facilities: [],
- ),
- RoomUpgradeDTO(
- name: 'Early Check In',
- price: '200',
- images: [],
- description:
- 'Check in to your room early and start enjoying your stay from the morning. Available from 10:00 AM.',
- id: '11',
- tags: [],
- type: 'service',
- facilities: [],
- ),
- RoomUpgradeDTO(
- name: 'Late Check Out',
- price: '150',
- images: [],
- description:
- 'Extend your stay and check out later in the day. Available until 2:00 PM.',
- id: '12',
- tags: ['popular'],
- type: 'service',
- facilities: [],
- ),
- RoomUpgradeDTO(
- name: 'Airport Transfer',
- price: '350',
- images: [],
- description:
- 'Convenient airport pickup and drop-off service with a professional driver and comfortable vehicle.',
- id: '13',
- tags: [],
- type: 'service',
- facilities: [],
- ),
- RoomUpgradeDTO(
- name: 'Valet Parking',
- price: '180',
- images: [],
- description:
- 'Professional valet parking service for your vehicle with secure storage and convenient access.',
- id: '14',
- tags: [],
- type: 'service',
- facilities: [],
- ),
-];
diff --git a/comwell_key_app/lib/up_sales/up_sales_catalog.dart b/comwell_key_app/lib/up_sales/up_sales_catalog.dart
index 65a7ace7..f81fac55 100644
--- a/comwell_key_app/lib/up_sales/up_sales_catalog.dart
+++ b/comwell_key_app/lib/up_sales/up_sales_catalog.dart
@@ -13,6 +13,9 @@ import 'package:comwell_key_app/up_sales/models/room_upgrade.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';
+import 'package:comwell_key_app/up_sales/models/room_upgrade_extra.dart';
+import 'package:comwell_key_app/up_sales/models/room_upgrade_list.dart';
class UpSalesCatalog extends StatelessWidget {
const UpSalesCatalog({super.key});
@@ -78,7 +81,29 @@ class UpSalesCatalog extends StatelessWidget {
style: theme.textTheme.headlineMedium),
),
const SizedBox(height: 8),
- RoomUpgradeCatalog(cubit: cubit),
+ RoomUpgradeCatalog(
+ upSales: cubit.upSales,
+ selectedUpSales: cubit.state.selectedUpSales,
+ onTap: (roomUpgrade) {
+ final isSelected =
+ cubit.state.selectedUpSales.contains(roomUpgrade);
+ if (isSelected) {
+ cubit.removeUpgrade(roomUpgrade);
+ } else {
+ cubit.addSelected(roomUpgrade);
+ }
+ },
+ onReadMoreTap:
+ (context, roomUpgrade, quantity, selectedUpSales) =>
+ handleReadMoreTapUpSales(
+ context: context,
+ routeName: AppRoutes.roomUpgrade.name,
+ cubit: cubit,
+ roomUpgrade: roomUpgrade,
+ quantity: quantity,
+ selectedUpSales: selectedUpSales,
+ ),
+ ),
const SizedBox(height: 24),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
@@ -86,7 +111,29 @@ class UpSalesCatalog extends StatelessWidget {
style: theme.textTheme.headlineMedium),
),
const SizedBox(height: 8),
- OtherUpgradeCatalog(cubit: cubit),
+ OtherUpgradeCatalog(
+ upSales: cubit.upSales,
+ selectedUpSales: cubit.state.selectedUpSales,
+ onTap: (roomUpgrade) {
+ final isSelected =
+ cubit.state.selectedUpSales.contains(roomUpgrade);
+ if (isSelected) {
+ cubit.removeUpgrade(roomUpgrade);
+ } else {
+ cubit.addSelected(roomUpgrade);
+ }
+ },
+ onReadMoreTap:
+ (context, roomUpgrade, quantity, selectedUpSales) =>
+ handleReadMoreTapUpSales(
+ context: context,
+ routeName: AppRoutes.otherUpgrade.name,
+ cubit: cubit,
+ roomUpgrade: roomUpgrade,
+ quantity: quantity,
+ selectedUpSales: selectedUpSales,
+ ),
+ ),
const SizedBox(height: 24),
],
),
@@ -94,7 +141,7 @@ class UpSalesCatalog extends StatelessWidget {
),
bottomNavigationBar: Column(mainAxisSize: MainAxisSize.min, children: [
const Divider(color: colorDivider),
- UpSalesBottomButton(onContinue: cubit.onContinue, children: [
+ UpSalesBottomButton(onContinue: cubit.onContinue, selectedUpSales: cubit.state.selectedUpSales, extrasTotalPrice: cubit.extrasTotalPrice, children: [
Text(
cubit.state.selectedUpSales.isEmpty
? "continue_without_up_sales".tr()
@@ -108,3 +155,33 @@ class UpSalesCatalog extends StatelessWidget {
});
}
}
+
+Future<void> handleReadMoreTapUpSales({
+ required BuildContext context,
+ required String routeName,
+ required dynamic cubit,
+ required RoomUpgrade roomUpgrade,
+ required int quantity,
+ required List<RoomUpgrade> selectedUpSales,
+}) async {
+ final dynamic extra;
+ if (routeName == AppRoutes.otherUpgrade.name) {
+ extra = RoomUpgradeExtra(roomUpgrade: roomUpgrade, quantity: quantity);
+ } else if (routeName == AppRoutes.roomUpgrade.name) {
+ extra = RoomUpgradeList(
+ roomUpgrade: roomUpgrade, roomUpgrades: selectedUpSales);
+ } else {
+ extra = null;
+ }
+ final roomUpgradeResponse = await context.pushNamed(routeName, extra: extra);
+ if (roomUpgradeResponse is List) {
+ if (roomUpgradeResponse[1] as bool) {
+ cubit.removeUpgrade(roomUpgradeResponse[0] as RoomUpgrade);
+ } else {
+ cubit.addSelected(roomUpgradeResponse[0] as RoomUpgrade);
+ }
+ }
+ if (roomUpgradeResponse is int) {
+ cubit.updateUpgradeQuantity(roomUpgrade, roomUpgradeResponse);
+ }
+}
diff --git a/comwell_key_app/lib/up_sales/up_sales_repository.dart b/comwell_key_app/lib/up_sales/up_sales_repository.dart
new file mode 100644
index 00000000..0bb5ebd8
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/up_sales_repository.dart
@@ -0,0 +1,372 @@
+import 'package:comwell_key_app/services/api.dart';
+import 'package:comwell_key_app/up_sales/mappers/room_upgrade_mapper.dart';
+import 'package:comwell_key_app/up_sales/models/dto/room_upgrade_dto.dart';
+import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
+import 'package:comwell_key_app/utils/json.dart';
+import 'package:comwell_key_app/up_sales/models/dto/room_facility_dto.dart';
+
+class UpSalesRepository {
+ final Api api = Api();
+
+ UpSalesRepository();
+
+ Future<Json> getUpSales() async {
+ final response = await api.fetchUpSales();
+ return response;
+ }
+
+ Future<List<RoomUpgrade>> getMockUpSales() async {
+ return mockRoomUpgrades.toRoomUpgrades();
+ }
+}
+
+// Mock data for RoomUpgrade and RoomFacility
+final List<RoomUpgradeDTO> mockRoomUpgrades = [
+ RoomUpgradeDTO(
+ name: 'Standard Double Room',
+ price: '1200',
+ images: ['assets/images/welcome_image.jpeg', 'assets/images/current_room.png', 'assets/images/no_current_bookings_background.jpeg'],
+ description:
+ 'A cozy room with a double bed, perfect for couples or solo travelers seeking comfort and convenience. A cozy room with a double bed, perfect for couples or solo travelers seeking comfort and convenience. A cozy room with a double bed, perfect for couples or solo travelers seeking comfort and convenience.',
+ id: '1',
+ tags: ['20'],
+ type: 'room',
+ facilities: [
+ RoomFacilityDTO(
+ name: '1x enkelseng',
+ icon: 'assets/icons/ic_single_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: '1x dobbelseng',
+ icon: 'assets/icons/ic_double_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: 'TV',
+ icon: 'assets/icons/ic_tv.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Gratis WiFi',
+ icon: 'assets/icons/ic_wifi.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Hårtørrer',
+ icon: 'assets/icons/ic_hairdryer.svg',
+ facilityType: 'Bathroom'),
+ RoomFacilityDTO(
+ name: 'Arbejdsplads',
+ icon: 'assets/icons/ic_desk.svg',
+ facilityType: 'Business'),
+ RoomFacilityDTO(
+ name: 'Roomservice',
+ icon: 'assets/icons/ic_service_bowl.svg',
+ facilityType: 'Service'),
+ RoomFacilityDTO(
+ name: 'Strygejern & -bræt',
+ icon: 'assets/icons/ic_iron.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Minibar',
+ icon: 'assets/icons/ic_minibar.svg',
+ facilityType: 'Room'),
+ ],
+ ),
+ RoomUpgradeDTO(
+ name: 'Junior Suite',
+ price: '1800',
+ images: ['assets/images/no_current_bookings_background.jpeg'],
+ description:
+ 'Spacious Junior Suite with a separate living area, ideal for guests who appreciate extra space and luxury. Spacious Junior Suite with a separate living area, ideal for guests who appreciate extra space and luxury. Spacious Junior Suite with a separate living area, ideal for guests who appreciate extra space and luxury.',
+ id: '2',
+ tags: ['35'],
+ type: 'room',
+ facilities: [
+ RoomFacilityDTO(
+ name: '1x enkelseng',
+ icon: 'assets/icons/ic_single_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: '2x dobbelseng',
+ icon: 'assets/icons/ic_double_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: 'TV',
+ icon: 'assets/icons/ic_tv.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Gratis WiFi',
+ icon: 'assets/icons/ic_wifi.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Hårtørrer',
+ icon: 'assets/icons/ic_hairdryer.svg',
+ facilityType: 'Bathroom'),
+ RoomFacilityDTO(
+ name: 'Badekar',
+ icon: 'assets/icons/ic_bathtub.svg',
+ facilityType: 'Bathroom'),
+ RoomFacilityDTO(
+ name: 'Arbejdsplads',
+ icon: 'assets/icons/ic_desk.svg',
+ facilityType: 'Business'),
+ RoomFacilityDTO(
+ name: 'Roomservice',
+ icon: 'assets/icons/ic_service_bowl.svg',
+ facilityType: 'Service'),
+ RoomFacilityDTO(
+ name: 'Strygejern & -bræt',
+ icon: 'assets/icons/ic_iron.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Terrasse',
+ icon: 'assets/icons/ic_balcony.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Te-køkken',
+ icon: 'assets/icons/ic_kettle.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Stue',
+ icon: 'assets/icons/ic_leather_chair.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Minibar',
+ icon: 'assets/icons/ic_minibar.svg',
+ facilityType: 'Room'),
+ ],
+ ),
+ RoomUpgradeDTO(
+ name: 'Suite',
+ price: '2500',
+ images: ['assets/images/current_room.png'],
+ description:
+ 'Our most luxurious suite, featuring a large living room, private terrace, and premium amenities for a memorable stay. Our most luxurious suite, featuring a large living room, private terrace, and premium amenities for a memorable stay. Our most luxurious suite, featuring a large living room, private terrace, and premium amenities for a memorable stay.',
+ id: '3',
+ tags: ['50'],
+ type: 'room',
+ facilities: [
+ RoomFacilityDTO(
+ name: '1x enkelseng',
+ icon: 'assets/icons/ic_single_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: 'TV',
+ icon: 'assets/icons/ic_tv.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Gratis WiFi',
+ icon: 'assets/icons/ic_wifi.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Hårtørrer',
+ icon: 'assets/icons/ic_hairdryer.svg',
+ facilityType: 'Bathroom'),
+ RoomFacilityDTO(
+ name: 'Badekar',
+ icon: 'assets/icons/ic_bathtub.svg',
+ facilityType: 'Bathroom'),
+ RoomFacilityDTO(
+ name: 'Arbejdsplads',
+ icon: 'assets/icons/ic_desk.svg',
+ facilityType: 'Business'),
+ RoomFacilityDTO(
+ name: 'Roomservice',
+ icon: 'assets/icons/ic_service_bowl.svg',
+ facilityType: 'Service'),
+ RoomFacilityDTO(
+ name: 'Strygejern & -bræt',
+ icon: 'assets/icons/ic_iron.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Terrasse',
+ icon: 'assets/icons/ic_balcony.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Te-køkken',
+ icon: 'assets/icons/ic_kettle.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Stue',
+ icon: 'assets/icons/ic_leather_chair.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Minibar',
+ icon: 'assets/icons/ic_minibar.svg',
+ facilityType: 'Room'),
+ ],
+ ),
+ RoomUpgradeDTO(
+ name: 'Standard Double Plus Room',
+ price: '1400',
+ images: ['assets/images/login_screen_background.png'],
+ description:
+ 'An upgraded double room with extra amenities and a modern touch, perfect for a relaxing stay. An upgraded double room with extra amenities and a modern touch, perfect for a relaxing stay. An upgraded double room with extra amenities and a modern touch, perfect for a relaxing stay.',
+ id: '4',
+ tags: ['25'],
+ type: 'room',
+ facilities: [
+ RoomFacilityDTO(
+ name: '2x dobbelseng',
+ icon: 'assets/icons/ic_double_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: 'TV',
+ icon: 'assets/icons/ic_tv.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Gratis WiFi',
+ icon: 'assets/icons/ic_wifi.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Hårtørrer',
+ icon: 'assets/icons/ic_hairdryer.svg',
+ facilityType: 'Bathroom'),
+ RoomFacilityDTO(
+ name: 'Arbejdsplads',
+ icon: 'assets/icons/ic_desk.svg',
+ facilityType: 'Business'),
+ RoomFacilityDTO(
+ name: 'Roomservice',
+ icon: 'assets/icons/ic_service_bowl.svg',
+ facilityType: 'Service'),
+ ],
+ ),
+ RoomUpgradeDTO(
+ name: 'Standard Twin Plus Room',
+ price: '1450',
+ images: ['assets/images/login_screen_background.png'],
+ description:
+ 'A spacious twin room with two single beds and modern facilities, ideal for friends or colleagues traveling together. A spacious twin room with two single beds and modern facilities, ideal for friends or colleagues traveling together. A spacious twin room with two single beds and modern facilities, ideal for friends or colleagues traveling together.',
+ id: '5',
+ tags: ['27'],
+ type: 'room',
+ facilities: [
+ RoomFacilityDTO(
+ name: '2x dobbelseng',
+ icon: 'assets/icons/ic_double_bed.svg',
+ facilityType: 'Bed'),
+ RoomFacilityDTO(
+ name: 'TV',
+ icon: 'assets/icons/ic_tv.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Gratis WiFi',
+ icon: 'assets/icons/ic_wifi.svg',
+ facilityType: 'Electronics'),
+ RoomFacilityDTO(
+ name: 'Hårtørrer',
+ icon: 'assets/icons/ic_hairdryer.svg',
+ facilityType: 'Bathroom'),
+ RoomFacilityDTO(
+ name: 'Arbejdsplads',
+ icon: 'assets/icons/ic_desk.svg',
+ facilityType: 'Business'),
+ RoomFacilityDTO(
+ name: 'Strygejern & -bræt',
+ icon: 'assets/icons/ic_iron.svg',
+ facilityType: 'Room'),
+ RoomFacilityDTO(
+ name: 'Minibar',
+ icon: 'assets/icons/ic_minibar.svg',
+ facilityType: 'Room'),
+ ],
+ ),
+ RoomUpgradeDTO(
+ name: 'Bottle of Champagne',
+ price: '450',
+ images: ['assets/images/catalog_image.png'],
+ description:
+ 'Celebrate your stay with a bottle of premium champagne and a selection of fine chocolates delivered to your room.',
+ id: '6',
+ tags: [],
+ type: 'other',
+ facilities: [],
+ ),
+ RoomUpgradeDTO(
+ name: 'Luxury Flower Arrangement',
+ price: '350',
+ images: ['assets/images/login_screen_background.png'],
+ description:
+ 'A beautiful bouquet of fresh seasonal flowers to brighten up your room and create a welcoming atmosphere.',
+ id: '7',
+ tags: [],
+ type: 'other',
+ facilities: [],
+ ),
+ RoomUpgradeDTO(
+ name: 'Romantic Evening Package',
+ price: '750',
+ images: ['assets/images/catalog_image.png'],
+ description:
+ 'Create a romantic atmosphere with rose petals, candles, champagne, and a special dessert for two.',
+ id: '8',
+ tags: [],
+ type: 'other',
+ facilities: [],
+ ),
+ RoomUpgradeDTO(
+ name: 'Breakfast in Bed',
+ price: '250',
+ images: ['assets/images/login_screen_background.png'],
+ description:
+ 'Start your day in luxury with a full breakfast served in the comfort of your room.',
+ id: '9',
+ tags: [],
+ type: 'other',
+ facilities: [],
+ ),
+ RoomUpgradeDTO(
+ name: 'Wellness Package',
+ price: '600',
+ images: ['assets/images/login_screen_background.png'],
+ description:
+ 'Indulge in a wellness experience with a selection of premium spa products, bath salts, and aromatherapy items.',
+ id: '10',
+ tags: [],
+ type: 'other',
+ facilities: [],
+ ),
+ RoomUpgradeDTO(
+ name: 'Early Check In',
+ price: '200',
+ images: [],
+ description:
+ 'Check in to your room early and start enjoying your stay from the morning. Available from 10:00 AM.',
+ id: '11',
+ tags: [],
+ type: 'service',
+ facilities: [],
+ ),
+ RoomUpgradeDTO(
+ name: 'Late Check Out',
+ price: '150',
+ images: [],
+ description:
+ 'Extend your stay and check out later in the day. Available until 2:00 PM.',
+ id: '12',
+ tags: ['popular'],
+ type: 'service',
+ facilities: [],
+ ),
+ RoomUpgradeDTO(
+ name: 'Airport Transfer',
+ price: '350',
+ images: [],
+ description:
+ 'Convenient airport pickup and drop-off service with a professional driver and comfortable vehicle.',
+ id: '13',
+ tags: [],
+ type: 'service',
+ facilities: [],
+ ),
+ RoomUpgradeDTO(
+ name: 'Valet Parking',
+ price: '180',
+ images: [],
+ description:
+ 'Professional valet parking service for your vehicle with secure storage and convenient access.',
+ id: '14',
+ tags: [],
+ type: 'service',
+ facilities: [],
+ ),
+];
diff --git a/comwell_key_app/lib/utils/locator.dart b/comwell_key_app/lib/utils/locator.dart
index 1ca1891a..5a0ccb61 100644
--- a/comwell_key_app/lib/utils/locator.dart
+++ b/comwell_key_app/lib/utils/locator.dart
@@ -9,8 +9,7 @@ import 'package:comwell_key_app/pregistration/pregistration_repository.dart';
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/cubit/up_sales_cubit.dart';
-import 'package:comwell_key_app/up_sales/up_sale_repository.dart';
+import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
import 'package:comwell_key_app/utils/seos_repository.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
@@ -46,6 +45,6 @@ void setupLocator() {
locator.registerFactory<NotificationsRepository>(
() => NotificationsRepository());
locator.registerFactory<ContactRepository>(() => ContactRepository());
- locator.registerFactory<UpSaleRepository>(() => UpSaleRepository());
+ locator.registerFactory<UpSalesRepository>(() => UpSalesRepository());
}
}
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 c38b689a..2bcc45d4 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
@@ -3,6 +3,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/profile/profile_repository.dart';
+import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
import 'package:comwell_key_app/utils/locator.dart';
import 'package:comwell_key_app/utils/seos_repository.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -16,15 +17,19 @@ class MockProfileRepository extends Mock implements ProfileRepository {}
class MockSeosRepository extends Mock implements SeosRepository {}
+class MockUpSalesRepository extends Mock implements UpSalesRepository {}
+
void main() {
// Declare the mock HomeRepository
late BookingDetailsRepository mockBookingDetailsRepository;
late ProfileRepository mockProfileRepository;
+ late UpSalesRepository mockUpSalesRepository;
// Setup function runs before every test
setUp(() {
// Initialize the mock HomeRepository
mockBookingDetailsRepository = MockBookingDetailsRepository();
mockProfileRepository = MockProfileRepository();
+ mockUpSalesRepository = MockUpSalesRepository();
setupLocator();
});
@@ -37,6 +42,7 @@ void main() {
CheckInRepository.mockBooking,
bookingDetailsRepository: mockBookingDetailsRepository,
profileRepository: mockProfileRepository,
+ upSaleRepository: mockUpSalesRepository,
);
},
act: (bloc) => bloc.add(InitialEvent()),
diff --git a/comwell_key_app/test/overview_test/overview_cubic_test.dart b/comwell_key_app/test/overview_test/overview_cubic_test.dart
index 23499d3f..c4bda538 100644
--- a/comwell_key_app/test/overview_test/overview_cubic_test.dart
+++ b/comwell_key_app/test/overview_test/overview_cubic_test.dart
@@ -46,7 +46,7 @@ void main() {
bookingDate: DateTime(2021, 10, 10),
digitalCard: true,
totalCharge: 100,
- status: ReservationStatus.newreservation,
+ reservationStatus: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890")
],
@@ -78,7 +78,7 @@ void main() {
bookingDate: DateTime(2021, 10, 10),
digitalCard: true,
totalCharge: 100,
- status: ReservationStatus.newreservation,
+ reservationStatus: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890")
],
@@ -132,7 +132,7 @@ void main() {
bookingDate: DateTime(2021, 10, 10),
digitalCard: true,
totalCharge: 100,
- status: ReservationStatus.newreservation,
+ reservationStatus: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890")),
expect: () => [
@@ -156,7 +156,7 @@ void main() {
bookingDate: DateTime(2021, 10, 10),
digitalCard: true,
totalCharge: 100,
- status: ReservationStatus.newreservation,
+ reservationStatus: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890")
],
diff --git a/comwell_key_app/test/overview_test/overview_repository_test.dart b/comwell_key_app/test/overview_test/overview_repository_test.dart
index 74fed1cb..66f295f5 100644
--- a/comwell_key_app/test/overview_test/overview_repository_test.dart
+++ b/comwell_key_app/test/overview_test/overview_repository_test.dart
@@ -15,7 +15,7 @@ void main() {
});
group('OverviewRepository', () {
- test('fetchAllBookingsForUser returns Bookings', () async {
+ test('fetchAllBookingsForUser returns Bookings', () async {
const userId = '1';
final bookings = Bookings(
current: [
@@ -36,7 +36,7 @@ void main() {
bookingDate: DateTime.now(),
digitalCard: true,
totalCharge: 100,
- status: ReservationStatus.newreservation,
+ reservationStatus: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890"
),
@@ -75,7 +75,7 @@ void main() {
bookingDate: DateTime.now(),
digitalCard: true,
totalCharge: 100,
- status: ReservationStatus.newreservation,
+ reservationStatus: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890"
);