6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit a5727b3b

AuthorEdmir Suljic<esu@dwarf.dk>
Date2025-06-24 09:56:16 +0200
Added another screen and resolved PR comments

Changed files

comwell_key_app/assets/translations/da-DK.json     |   6 +-
 comwell_key_app/assets/translations/en-US.json     |   6 +-
 .../models/structured_text.g.dart                  |  33 +++--
 .../check_out/components/accept_terms_toggle.dart  |   2 +-
 comwell_key_app/lib/common/const.dart              |   4 +
 .../hotel_information/models/structured_text.dart  |  16 +--
 .../hotel_information/pages/spa_facility_page.dart |   4 -
 .../components/balance_bottom_sheet.dart           |   4 +-
 .../components/approve_conditions_widget.dart      |   6 +-
 .../components/prereg_bottom_button.dart           |   7 +-
 .../pregistration/cubit/preregistration_cubit.dart |   4 +-
 .../pregistration/cubit/preregistration_state.dart |  61 ++++----
 .../pages/prereg_confirmation_page.dart            |   6 +-
 .../pages/prereg_up_sales_catalog_page.dart        |  94 ++++++------
 comwell_key_app/lib/routing/app_router.dart        |  47 +++++-
 comwell_key_app/lib/routing/app_routes.dart        |   2 +
 .../components/catalog/room_uprade_catalog.dart    |   5 +-
 .../components/catalog/service_catalog.dart        |   5 +-
 .../components/facilities_bottom_sheet.dart        |  35 ++---
 .../components/up_sales_bottom_button.dart         |   7 +-
 .../components/up_sales_services_widget.dart       |   3 +-
 .../components/up_sales_upgrades_widget.dart       |  18 +--
 .../lib/up_sales/cubit/up_sales_cubit.dart         |  10 ++
 .../lib/up_sales/cubit/up_sales_state.dart         |  24 ++--
 .../lib/up_sales/models/room_facility.dart         |   3 +-
 .../lib/up_sales/pages/other_upgrade_page.dart     |   3 +-
 .../up_sales/pages/up_sale_confirmation_page.dart  | 159 +++++++++++++++++++++
 .../up_sales/pages/up_sales_processing_page.dart   |  85 +++++++++++
 comwell_key_app/lib/up_sales/up_sales_catalog.dart |   2 +-
 29 files changed, 475 insertions(+), 186 deletions(-)

Diff

diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index bd6b2978..9ba8e60b 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -171,7 +171,7 @@
"checkout_page_payment_club_points_title": "Brug Comwell Club Point",
"checkout_page_payment_club_points_subtitle": "Du har {} point, anvend og spar {} kr.",
"checkout_page_payment_payment_title": "Betal med {}",
- "checkout_page_payment_accept_terms": "Accepter betingelserne",
+ "accept_terms": "Accepter betingelserne",
"checkout_page_payment_dialog_title": "Er du sikker på du vil checke ud af hotellet?",
"checkout_page_payment_dialog_subtitle": "Når du bekræfter, har du 30 minutter til at forlade dit værelse.",
"checkout_page_payment_dialog_confirm": "Ja, check ud nu",
@@ -254,8 +254,8 @@
"check_in_button_timer_hours_minutes": "Om {} timer og {} minutter",
"check_in_button_timer_minutes": "Om {} minutter",
"check_in_button_timer_seconds": "Om {} sekunder",
- "payment_cards_approve_conditions_title": "Jeg accepter ",
- "payment_cards_approve_conditions_subtitle": "betingelserne",
+ "approve_conditions_title": "Jeg accepter ",
+ "approve_conditions_subtitle": "betingelserne",
"up_sales_title": "Tidlig check-in",
"up_sales_subtitle": "Med tidlig check-in kan du checke ind kl. 13.00 i stedet for kl. 15.00.",
"up_sales_popular": "POPULÆR",
diff --git a/comwell_key_app/assets/translations/en-US.json b/comwell_key_app/assets/translations/en-US.json
index 305662be..a002d4eb 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -170,7 +170,7 @@
"checkout_page_payment_club_points_title": "Use Comwell Club Points",
"checkout_page_payment_club_points_subtitle": "You have {} point, use them and save {} kr.",
"checkout_page_payment_payment_title": "Pay with {}",
- "checkout_page_payment_accept_terms": "Accept terms and conditions",
+ "accept_terms": "Accept terms and conditions",
"checkout_page_payment_dialog_title": "Are you sure you want to check out?",
"checkout_page_payment_dialog_subtitle": "When you check out, you have 30 minutes to leave your room",
"checkout_page_payment_dialog_confirm": "Yes, check out now",
@@ -257,8 +257,8 @@
"check_in_button_timer_hours_minutes": "In {} hours and {} minutes",
"check_in_button_timer_minutes": "In {} minutes",
"check_in_button_timer_seconds": "In {} seconds",
- "payment_cards_approve_conditions_title": "I accept ",
- "payment_cards_approve_conditions_subtitle": "terms and conditions",
+ "approve_conditions_title": "I accept ",
+ "approve_conditions_subtitle": "terms and conditions",
"up_sales_title": "Early check-in",
"up_sales_subtitle": "With early check-in you can check in at 13.00 instead of 15.00.",
"up_sales_popular": "POPULAR",
diff --git a/comwell_key_app/lib/.generated/hotel_information/models/structured_text.g.dart b/comwell_key_app/lib/.generated/hotel_information/models/structured_text.g.dart
index c6313d91..2cc00123 100644
--- a/comwell_key_app/lib/.generated/hotel_information/models/structured_text.g.dart
+++ b/comwell_key_app/lib/.generated/hotel_information/models/structured_text.g.dart
@@ -82,35 +82,35 @@ Map<String, dynamic> _$PhoneContactStructuredTextModelToJson(
ImageWidgetStructuredTextModel _$ImageWidgetStructuredTextModelFromJson(
Map json) =>
ImageWidgetStructuredTextModel(
- type: json['\x024type'] as String? ?? 'ImageWidgetStructuredTextModel',
+ type: json[r'$type'] as String? ?? 'ImageWidgetStructuredTextModel',
image: json['image'] as String,
);
Map<String, dynamic> _$ImageWidgetStructuredTextModelToJson(
ImageWidgetStructuredTextModel instance) =>
<String, dynamic>{
- '\x024type': instance.type,
+ r'$type': instance.type,
'image': instance.image,
};
SpaBookingLinkStructuredTextModel _$SpaBookingLinkStructuredTextModelFromJson(
Map json) =>
SpaBookingLinkStructuredTextModel(
- type: json['\x024type'] as String? ?? 'SpaBookingLinkStructuredTextModel',
+ type: json[r'$type'] as String? ?? 'SpaBookingLinkStructuredTextModel',
link: json['link'] as String,
);
Map<String, dynamic> _$SpaBookingLinkStructuredTextModelToJson(
SpaBookingLinkStructuredTextModel instance) =>
<String, dynamic>{
- '\x024type': instance.type,
+ r'$type': instance.type,
'link': instance.link,
};
HotelInformationListTileStructuredTextModel
_$HotelInformationListTileStructuredTextModelFromJson(Map json) =>
HotelInformationListTileStructuredTextModel(
- type: json['\x024type'] as String? ??
+ type: json[r'$type'] as String? ??
'HotelInformationListTileStructuredTextModel',
iconPath: json['iconPath'] as String,
title: json['title'] as String,
@@ -119,7 +119,7 @@ HotelInformationListTileStructuredTextModel
Map<String, dynamic> _$HotelInformationListTileStructuredTextModelToJson(
HotelInformationListTileStructuredTextModel instance) =>
<String, dynamic>{
- '\x024type': instance.type,
+ r'$type': instance.type,
'iconPath': instance.iconPath,
'title': instance.title,
};
@@ -127,49 +127,48 @@ Map<String, dynamic> _$HotelInformationListTileStructuredTextModelToJson(
MapsBottomModalStructuredTextModel _$MapsBottomModalStructuredTextModelFromJson(
Map json) =>
MapsBottomModalStructuredTextModel(
- type:
- json['\x024type'] as String? ?? 'MapsBottomModalStructuredTextModel',
+ type: json[r'$type'] as String? ?? 'MapsBottomModalStructuredTextModel',
address: json['address'] as String,
);
Map<String, dynamic> _$MapsBottomModalStructuredTextModelToJson(
MapsBottomModalStructuredTextModel instance) =>
<String, dynamic>{
- '\x024type': instance.type,
+ r'$type': instance.type,
'address': instance.address,
};
OpeningHoursStructuredTextModel _$OpeningHoursStructuredTextModelFromJson(
Map json) =>
OpeningHoursStructuredTextModel(
- type: json['\x024type'] as String? ?? 'OpeningHoursStructuredTextModel',
+ type: json[r'$type'] as String? ?? 'OpeningHoursStructuredTextModel',
openingHours: json['openingHours'] as String,
);
Map<String, dynamic> _$OpeningHoursStructuredTextModelToJson(
OpeningHoursStructuredTextModel instance) =>
<String, dynamic>{
- '\x024type': instance.type,
+ r'$type': instance.type,
'openingHours': instance.openingHours,
};
PageTitleStructuredTextModel _$PageTitleStructuredTextModelFromJson(Map json) =>
PageTitleStructuredTextModel(
- type: json['\x024type'] as String? ?? 'PageTitleStructuredTextModel',
+ type: json[r'$type'] as String? ?? 'PageTitleStructuredTextModel',
title: json['title'] as String,
);
Map<String, dynamic> _$PageTitleStructuredTextModelToJson(
PageTitleStructuredTextModel instance) =>
<String, dynamic>{
- '\x024type': instance.type,
+ r'$type': instance.type,
'title': instance.title,
};
PracticalInformationStructuredTextModel
_$PracticalInformationStructuredTextModelFromJson(Map json) =>
PracticalInformationStructuredTextModel(
- type: json['\x024type'] as String? ??
+ type: json[r'$type'] as String? ??
'PracticalInformationStructuredTextModel',
restaurantId: json['restaurantId'] as String,
);
@@ -177,19 +176,19 @@ PracticalInformationStructuredTextModel
Map<String, dynamic> _$PracticalInformationStructuredTextModelToJson(
PracticalInformationStructuredTextModel instance) =>
<String, dynamic>{
- '\x024type': instance.type,
+ r'$type': instance.type,
'restaurantId': instance.restaurantId,
};
EmailStructuredTextModel _$EmailStructuredTextModelFromJson(Map json) =>
EmailStructuredTextModel(
- type: json['\x024type'] as String? ?? 'EmailStructuredTextModel',
+ type: json[r'$type'] as String? ?? 'EmailStructuredTextModel',
email: json['email'] as String,
);
Map<String, dynamic> _$EmailStructuredTextModelToJson(
EmailStructuredTextModel instance) =>
<String, dynamic>{
- '\x024type': instance.type,
+ r'$type': instance.type,
'email': instance.email,
};
diff --git a/comwell_key_app/lib/check_out/components/accept_terms_toggle.dart b/comwell_key_app/lib/check_out/components/accept_terms_toggle.dart
index 7107c44c..3ef7810f 100644
--- a/comwell_key_app/lib/check_out/components/accept_terms_toggle.dart
+++ b/comwell_key_app/lib/check_out/components/accept_terms_toggle.dart
@@ -34,7 +34,7 @@ class AcceptTermsToggle extends StatelessWidget {
cubit.showTermsAndConditions();
},
child: Text(
- "checkout_page_payment_accept_terms".tr(),
+ "accept_terms".tr(),
style: TextStyle(
color: sandColor[80],
decoration: TextDecoration.underline,
diff --git a/comwell_key_app/lib/common/const.dart b/comwell_key_app/lib/common/const.dart
index fd49aa8f..c63011b8 100644
--- a/comwell_key_app/lib/common/const.dart
+++ b/comwell_key_app/lib/common/const.dart
@@ -4,6 +4,10 @@ const isEndpointSetup = 'isEndpointSetup';
const hasKey = 'hasKey';
const needsScaffold = 'needsScaffold';
const kComwellAppBarHeight = 130.0;
+const kPlaceholderImage = 'assets/images/catalog_image.png';
+const kUpSalesServiceWidgetWidthLarge = 328.0;
+const kUpSalesServiceWidgetHeightSmall = 180.0;
+const kUpSalesServiceWidgetHeightLarge = 268.0;
// Adyen
diff --git a/comwell_key_app/lib/hotel_information/models/structured_text.dart b/comwell_key_app/lib/hotel_information/models/structured_text.dart
index d057cedc..2505f3b2 100644
--- a/comwell_key_app/lib/hotel_information/models/structured_text.dart
+++ b/comwell_key_app/lib/hotel_information/models/structured_text.dart
@@ -152,7 +152,7 @@ class PhoneContactStructuredTextModel implements StructuredTextBlock {
@JsonSerializable()
class ImageWidgetStructuredTextModel implements StructuredTextBlock {
- @JsonKey(name: '4type')
+ @JsonKey(name: '\$type')
final String type;
final String image;
@@ -171,7 +171,7 @@ class ImageWidgetStructuredTextModel implements StructuredTextBlock {
@JsonSerializable()
class SpaBookingLinkStructuredTextModel implements StructuredTextBlock {
- @JsonKey(name: '4type')
+ @JsonKey(name: '\$type')
final String type;
final String link;
@@ -190,7 +190,7 @@ class SpaBookingLinkStructuredTextModel implements StructuredTextBlock {
@JsonSerializable()
class HotelInformationListTileStructuredTextModel implements StructuredTextBlock {
- @JsonKey(name: '4type')
+ @JsonKey(name: '\$type')
final String type;
final String iconPath;
final String title;
@@ -211,7 +211,7 @@ class HotelInformationListTileStructuredTextModel implements StructuredTextBlock
@JsonSerializable()
class MapsBottomModalStructuredTextModel implements StructuredTextBlock {
- @JsonKey(name: '4type')
+ @JsonKey(name: '\$type')
final String type;
final String address;
@@ -230,7 +230,7 @@ class MapsBottomModalStructuredTextModel implements StructuredTextBlock {
@JsonSerializable()
class OpeningHoursStructuredTextModel implements StructuredTextBlock {
- @JsonKey(name: '4type')
+ @JsonKey(name: '\$type')
final String type;
final String openingHours;
@@ -249,7 +249,7 @@ class OpeningHoursStructuredTextModel implements StructuredTextBlock {
@JsonSerializable()
class PageTitleStructuredTextModel implements StructuredTextBlock {
- @JsonKey(name: '4type')
+ @JsonKey(name: '\$type')
final String type;
final String title;
@@ -268,7 +268,7 @@ class PageTitleStructuredTextModel implements StructuredTextBlock {
@JsonSerializable()
class PracticalInformationStructuredTextModel implements StructuredTextBlock {
- @JsonKey(name: '4type')
+ @JsonKey(name: '\$type')
final String type;
final String restaurantId;
@@ -287,7 +287,7 @@ class PracticalInformationStructuredTextModel implements StructuredTextBlock {
@JsonSerializable()
class EmailStructuredTextModel implements StructuredTextBlock {
- @JsonKey(name: '4type')
+ @JsonKey(name: '\$type')
final String type;
final String email;
diff --git a/comwell_key_app/lib/hotel_information/pages/spa_facility_page.dart b/comwell_key_app/lib/hotel_information/pages/spa_facility_page.dart
index f6e33a88..bec3e2f9 100644
--- a/comwell_key_app/lib/hotel_information/pages/spa_facility_page.dart
+++ b/comwell_key_app/lib/hotel_information/pages/spa_facility_page.dart
@@ -43,10 +43,6 @@ class SpaFacilityPage extends StatelessWidget {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
- const Divider(
- color: colorDivider,
- height: 0,
- ),
Row(
children: [
Expanded(
diff --git a/comwell_key_app/lib/my_booking/components/balance_bottom_sheet.dart b/comwell_key_app/lib/my_booking/components/balance_bottom_sheet.dart
index 0ea5ae46..3302f360 100644
--- a/comwell_key_app/lib/my_booking/components/balance_bottom_sheet.dart
+++ b/comwell_key_app/lib/my_booking/components/balance_bottom_sheet.dart
@@ -174,7 +174,9 @@ class BalanceBottomSheet extends StatelessWidget {
fontWeight: FontWeight.w600,
),
),
- Text("${balance.toInt()} kr.",
+ Text(
+ "total_charge_value"
+ .tr(args: [balance.toString()]),
style: theme.textTheme.bodyMedium?.copyWith(
color: Colors.white,
fontSize: 16,
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 ac036379..6783a924 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
@@ -21,7 +21,7 @@ class ApproveConditionsWidget extends StatelessWidget {
activeColor: sandColor,
checkColor: Colors.white,
side: const BorderSide(color: Colors.grey),
- value: cubit.state.isTermsAccepted,
+ value: cubit.state.termsAccepted,
onChanged: (value) {
cubit.onTermsAndConditionsToggled(value ?? false);
},
@@ -30,11 +30,11 @@ class ApproveConditionsWidget extends StatelessWidget {
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
- Text('payment_cards_approve_conditions_title'.tr(), style: theme.textTheme.bodyMedium?.copyWith(
+ Text('approve_conditions_title'.tr(), style: theme.textTheme.bodyMedium?.copyWith(
color: colorHeadlineText,
)),
Text(
- 'payment_cards_approve_conditions_subtitle'.tr(),
+ 'approve_conditions_subtitle'.tr(),
style: theme.textTheme.bodyMedium?.copyWith(
color: sandColor,
decoration: TextDecoration.underline,
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 db1d1e2d..438ce69f 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,5 @@
import 'package:comwell_key_app/pregistration/cubit/preregistration_cubit.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:flutter/material.dart';
class PreregBottomButton extends StatelessWidget {
@@ -15,10 +16,6 @@ class PreregBottomButton extends StatelessWidget {
// BOTTOM NAVIGATION
mainAxisSize: MainAxisSize.min,
children: [
- const Divider(
- color: Colors.black12,
- height: 0,
- ),
Row(
children: [
Expanded(
@@ -34,7 +31,7 @@ class PreregBottomButton extends StatelessWidget {
if (states.contains(WidgetState.disabled)) {
return Colors.grey;
}
- return const Color(0xffAA8D65);
+ return sandColor;
}),
foregroundColor:
const WidgetStatePropertyAll(Colors.white)),
diff --git a/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart b/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
index 6d27f586..3eec8077 100644
--- a/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
+++ b/comwell_key_app/lib/pregistration/cubit/preregistration_cubit.dart
@@ -317,7 +317,7 @@ class PreregistrationCubit extends Cubit<PreregistrationState> {
case PreregistrationPage.address:
return isAddressValid && isPostalCodeValid && isCityValid;
case PreregistrationPage.payment:
- return state.isTermsAccepted;
+ return state.termsAccepted;
case PreregistrationPage.upSales:
return true;
case PreregistrationPage.confirmation:
@@ -346,7 +346,7 @@ class PreregistrationCubit extends Cubit<PreregistrationState> {
}
void onTermsAndConditionsToggled(bool toggle) {
- emit(state.copyWith(isTermsAccepted: toggle));
+ emit(state.copyWith(termsAccepted: toggle));
}
void addSelected(RoomUpgrade roomUpgrade) {
diff --git a/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart b/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
index 0f18fd0d..495df08c 100644
--- a/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
+++ b/comwell_key_app/lib/pregistration/cubit/preregistration_state.dart
@@ -1,15 +1,14 @@
-
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 '../../profile_settings/model/user.dart';
-class PreregistrationState extends UpSalesState {
+class PreregistrationState extends UpSalesState {
final bool forceUpdate;
final User? user;
final CountryCode? countryCode;
- final String? phoneNumber;
+ final String? phoneNumber;
final bool missingInformation;
final int numOfExtras;
final int extrasTotalPrice;
@@ -17,7 +16,8 @@ class PreregistrationState extends UpSalesState {
final bool isPhoneNumberValid;
final bool isFirstNameValid;
final bool isLastNameValid;
- final bool isTermsAccepted;
+ @override
+ final bool termsAccepted;
final bool isAddressValid;
final bool isPostalCodeValid;
final bool isCityValid;
@@ -39,7 +39,7 @@ class PreregistrationState extends UpSalesState {
this.isPhoneNumberValid = false,
this.isFirstNameValid = false,
this.isLastNameValid = false,
- this.isTermsAccepted = false,
+ this.termsAccepted = false,
this.isAddressValid = false,
this.isPostalCodeValid = false,
this.isCityValid = false,
@@ -60,7 +60,7 @@ class PreregistrationState extends UpSalesState {
isPhoneNumberValid,
isFirstNameValid,
isLastNameValid,
- isTermsAccepted,
+ termsAccepted,
isAddressValid,
isPostalCodeValid,
isCityValid,
@@ -86,34 +86,33 @@ class PreregistrationState extends UpSalesState {
bool? isPhoneNumberValid,
bool? isFirstNameValid,
bool? isLastNameValid,
- bool? isTermsAccepted,
+ bool? termsAccepted,
bool? isAddressValid,
bool? isPostalCodeValid,
- bool? isCityValid
+ 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,
- );
+ 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,
+ termsAccepted: termsAccepted ?? this.termsAccepted,
+ 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_confirmation_page.dart b/comwell_key_app/lib/pregistration/pages/prereg_confirmation_page.dart
index 2949c5ff..c7ac6ce1 100644
--- a/comwell_key_app/lib/pregistration/pages/prereg_confirmation_page.dart
+++ b/comwell_key_app/lib/pregistration/pages/prereg_confirmation_page.dart
@@ -123,9 +123,9 @@ class PreregConfirmationPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
- "${cubit.extrasTotalPrice} kr.",
- style: theme.textTheme.bodyMedium
- ),
+ "total_charge_value"
+ .tr(args: [cubit.extrasTotalPrice.toString()]),
+ style: theme.textTheme.bodyMedium),
Text(
"preregistration_confirmation_extras_card_subtitle".tr(),
style: theme.textTheme.bodySmall?.copyWith(
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 dc6e7b58..b33542f2 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
@@ -33,8 +33,6 @@ class PreregUpSalesCatalogPage extends StatelessWidget {
padding: const EdgeInsets.only(
top: 24,
bottom: 100,
- left: 0,
- right: 0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -71,27 +69,30 @@ class PreregUpSalesCatalogPage extends StatelessWidget {
),
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,
- ),
+ 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(
@@ -101,26 +102,27 @@ class PreregUpSalesCatalogPage extends StatelessWidget {
),
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,
- ),
+ 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),
],
@@ -142,11 +144,13 @@ class PreregUpSalesCatalogPage extends StatelessWidget {
if (routeName == AppRoutes.otherUpgrade.name) {
extra = RoomUpgradeExtra(roomUpgrade: roomUpgrade, quantity: quantity);
} else if (routeName == AppRoutes.roomUpgrade.name) {
- extra = RoomUpgradeList(roomUpgrade: roomUpgrade, roomUpgrades: selectedUpSales);
+ extra = RoomUpgradeList(
+ roomUpgrade: roomUpgrade, roomUpgrades: selectedUpSales);
} else {
extra = null;
}
- final roomUpgradeResponse = await context.pushNamed(routeName, extra: extra);
+ final roomUpgradeResponse =
+ await context.pushNamed(routeName, extra: extra);
if (roomUpgradeResponse is List) {
if (roomUpgradeResponse[1] as bool) {
cubit.removeUpgrade(roomUpgradeResponse[0] as RoomUpgrade);
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index b69b2311..11673a49 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -49,10 +49,13 @@ import 'package:comwell_key_app/routing/go_router_observer.dart';
import 'package:comwell_key_app/share/cubit/share_booking_cubit.dart';
import 'package:comwell_key_app/share/share_booking_page.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/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/pages/up_sale_confirmation_page.dart';
+import 'package:comwell_key_app/up_sales/pages/up_sales_processing_page.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';
@@ -110,8 +113,8 @@ GoRouter goRouter() {
ShellRoute(
navigatorKey: _shellNavigatorKey,
parentNavigatorKey: _rootNavigatorKey,
- pageBuilder: (context, state, child) {
- return NoTransitionPage(
+ pageBuilder: (context, state, child) {
+ return NoTransitionPage(
child: BlocProvider<HotelInformationCubit>(
create: (BuildContext context) => HotelInformationCubit(
hotelInformationRepository:
@@ -279,7 +282,8 @@ GoRouter goRouter() {
builder: (context, state) {
final booking = state.extra as Booking;
return BlocProvider<BookingDetailsBloc>(
- create: (BuildContext context) => BookingDetailsBloc(booking,
+ create: (BuildContext context) => BookingDetailsBloc(
+ booking,
bookingDetailsRepository:
locator<BookingDetailsRepository>(),
profileRepository: locator<ProfileRepository>(),
@@ -399,7 +403,8 @@ GoRouter goRouter() {
final roomUpgradeList = state.extra as RoomUpgradeList;
return BlocProvider(
create: (context) =>
- UpSalesCubit(upSaleRepository: locator<UpSalesRepository>())..init(),
+ UpSalesCubit(upSaleRepository: locator<UpSalesRepository>())
+ ..init(),
child: RoomUpgradePage(roomUpgradeList: roomUpgradeList),
);
},
@@ -410,11 +415,41 @@ GoRouter goRouter() {
builder: (context, state) {
final roomUpgrade = state.extra as RoomUpgradeExtra;
return BlocProvider(
- create: (context) =>
- UpSalesCubit.withExtra(upSaleRepository: locator<UpSalesRepository>(), extra: roomUpgrade),
+ create: (context) => UpSalesCubit.withExtra(
+ upSaleRepository: locator<UpSalesRepository>(),
+ extra: roomUpgrade),
child: OtherUpgradePage(extra: roomUpgrade),
);
}),
+ GoRoute(
+ path: "/${AppRoutes.upSaleConfirmation.name}",
+ name: AppRoutes.upSaleConfirmation.name,
+ builder: (context, state) {
+ final extras = state.extra as List<dynamic>;
+ final selectedUpSales = extras[0] as List<RoomUpgrade>;
+ final extrasTotalPrice = extras[1] as int;
+ return BlocProvider(
+ create: (context) =>
+ UpSalesCubit(upSaleRepository: locator<UpSalesRepository>())
+ ..init(),
+ child: UpSaleConfirmationPage(
+ selectedUpSales: selectedUpSales,
+ extrasTotalPrice: extrasTotalPrice),
+ );
+ },
+ ),
+ GoRoute(
+ path: "/${AppRoutes.upSalesAnimation.name}",
+ name: AppRoutes.upSalesAnimation.name,
+ builder: (context, state) {
+ return BlocProvider(
+ create: (context) =>
+ UpSalesCubit(upSaleRepository: locator<UpSalesRepository>())
+ ..init(),
+ child: UpSalesProcessingPage(),
+ );
+ },
+ ),
/* GoRoute(
path: "/keys",
name: AppRoutes.keys.name,
diff --git a/comwell_key_app/lib/routing/app_routes.dart b/comwell_key_app/lib/routing/app_routes.dart
index 88ce9e04..1eef87ac 100644
--- a/comwell_key_app/lib/routing/app_routes.dart
+++ b/comwell_key_app/lib/routing/app_routes.dart
@@ -31,4 +31,6 @@ enum AppRoutes {
upSalesCatalog,
roomUpgrade,
otherUpgrade,
+ upSaleConfirmation,
+ upSalesAnimation,
}
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 c2078832..5b47a369 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
@@ -1,3 +1,4 @@
+import 'package:comwell_key_app/common/const.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/up_sales/components/up_sales_upgrades_widget.dart';
@@ -34,8 +35,8 @@ class RoomUpgradeCatalog extends StatelessWidget {
itemCount: roomUpSales.length,
itemBuilder: (context, index) {
return UpSalesUpgradesWidget(
- width: 328,
- height: 268,
+ width: kUpSalesServiceWidgetWidthLarge,
+ height: kUpSalesServiceWidgetHeightLarge,
roomUpgrade: roomUpSales.elementAt(index),
isSelected: selectedUpSales.contains(roomUpSales.elementAt(index)),
routeName: AppRoutes.roomUpgrade.name,
diff --git a/comwell_key_app/lib/up_sales/components/catalog/service_catalog.dart b/comwell_key_app/lib/up_sales/components/catalog/service_catalog.dart
index c1923f03..a4c7fb39 100644
--- a/comwell_key_app/lib/up_sales/components/catalog/service_catalog.dart
+++ b/comwell_key_app/lib/up_sales/components/catalog/service_catalog.dart
@@ -1,3 +1,4 @@
+import 'package:comwell_key_app/common/const.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/up_sales/components/up_sales_services_widget.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
@@ -34,7 +35,7 @@ class ServiceCatalog extends StatelessWidget {
}
return SizedBox(
- height: height ?? 180,
+ height: height ?? kUpSalesServiceWidgetHeightSmall,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: services.length,
@@ -42,7 +43,7 @@ class ServiceCatalog extends StatelessWidget {
final isPopular = services.elementAt(index).tags.contains('popular');
return UpSalesServicesWidget(
showRadioButton: showRadioButton,
- width: 328,
+ width: kUpSalesServiceWidgetWidthLarge,
roomUpgrade: services.elementAt(index),
isSelected: selectedUpSales?.map((e) => e.id).toList().contains(services.elementAt(index).id) ?? false,
isPopular: isPopular,
diff --git a/comwell_key_app/lib/up_sales/components/facilities_bottom_sheet.dart b/comwell_key_app/lib/up_sales/components/facilities_bottom_sheet.dart
index 1e55cdf0..1774c5ff 100644
--- a/comwell_key_app/lib/up_sales/components/facilities_bottom_sheet.dart
+++ b/comwell_key_app/lib/up_sales/components/facilities_bottom_sheet.dart
@@ -11,25 +11,14 @@ class FacilitiesBottomSheet extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
- // Group facilities for display (mocked for now)
- final Map<String, List<RoomFacility>> grouped = {
- 'SENGETYPER':
- facilities.where((f) => f.facilityType == FacilityType.bed).toList(),
- 'ELEKTRONIK': facilities
- .where((f) => f.facilityType == FacilityType.electronics)
- .toList(),
- 'BADEVÆRELSE': facilities
- .where((f) => f.facilityType == FacilityType.bathroom)
- .toList(),
- 'BUSINESS': facilities
- .where((f) => f.facilityType == FacilityType.business)
- .toList(),
- 'SERVICE': facilities
- .where((f) => f.facilityType == FacilityType.service)
- .toList(),
- 'VÆRELSESFACILITETER':
- facilities.where((f) => f.facilityType == FacilityType.room).toList(),
- };
+ // Group facilities for display dynamically
+ final Map<FacilityType, List<RoomFacility>> grouped = {};
+ for (final type in FacilityType.values) {
+ final facilitiesOfType = facilities.where((f) => f.facilityType == type).toList();
+ if (facilitiesOfType.isNotEmpty) {
+ grouped[type] = facilitiesOfType;
+ }
+ }
return Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
@@ -59,18 +48,18 @@ class FacilitiesBottomSheet extends StatelessWidget {
...grouped.entries.map((entry) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Text(entry.key,
+ Text(entry.key.name.toUpperCase(),
style: theme.textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.bold,
color: colorHeadlineText)),
const SizedBox(height: 8),
Wrap(
- direction: entry.key == 'SENGETYPER'
+ direction: entry.key == FacilityType.bed
? Axis.horizontal
: Axis.vertical,
spacing: 16,
runSpacing: 8,
- children: entry.key == 'SENGETYPER'
+ children: entry.key == FacilityType.bed
? entry.value
.map((f) => Container(
width: 175,
@@ -90,7 +79,7 @@ class FacilitiesBottomSheet extends StatelessWidget {
.toList(),
),
const SizedBox(height: 16),
- if (entry.key != 'SENGETYPER')
+ if (entry.key != FacilityType.bed)
const Column(
children: [
Divider(
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 ce063926..eacce688 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,7 +1,9 @@
+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/confirm_up_sales_dialog.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
class UpSalesBottomButton extends StatelessWidget {
final List<Widget> children;
@@ -35,10 +37,7 @@ class UpSalesBottomButton extends StatelessWidget {
onContinue();
}
if (selectedUpSales.isNotEmpty) {
- showDialog<void>(
- context: context,
- builder: (context) => ConfirmUpSalesDialog(onContinue: onContinue, extrasTotalPrice: extrasTotalPrice),
- );
+ context.pushNamed(AppRoutes.upSaleConfirmation.name, extra: [selectedUpSales, extrasTotalPrice]);
}
},
style: ButtonStyle(
diff --git a/comwell_key_app/lib/up_sales/components/up_sales_services_widget.dart b/comwell_key_app/lib/up_sales/components/up_sales_services_widget.dart
index 72ccac11..779b32ba 100644
--- a/comwell_key_app/lib/up_sales/components/up_sales_services_widget.dart
+++ b/comwell_key_app/lib/up_sales/components/up_sales_services_widget.dart
@@ -2,6 +2,7 @@ import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/up_sales/components/comwell_radio_button.dart';
import 'package:comwell_key_app/up_sales/components/tags.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
+import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
class UpSalesServicesWidget extends StatelessWidget {
@@ -58,7 +59,7 @@ class UpSalesServicesWidget extends StatelessWidget {
Row(
children: [
Text(
- '${roomUpgrade.price} kr.',
+ "total_charge_value".tr(args: [roomUpgrade.price]),
style: theme.textTheme.headlineMedium,
),
const SizedBox(width: 8),
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 fc626cfd..1ce9d80e 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
@@ -1,3 +1,4 @@
+import 'package:comwell_key_app/common/const.dart';
import 'package:comwell_key_app/up_sales/components/comwell_radio_button.dart';
import 'package:comwell_key_app/up_sales/components/upgrades_counter.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
@@ -11,7 +12,7 @@ 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;
@@ -31,9 +32,8 @@ class UpSalesUpgradesWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- final quantity = selectedUpSales
- .where((element) => element.id == roomUpgrade.id)
- .length;
+ final quantity =
+ selectedUpSales.where((element) => element.id == roomUpgrade.id).length;
return Container(
width: width,
@@ -55,7 +55,7 @@ class UpSalesUpgradesWidget extends StatelessWidget {
topRight: Radius.circular(10),
),
child: Image.asset(
- roomUpgrade.images!.first,
+ roomUpgrade.images?.first ?? kPlaceholderImage,
height: 180,
width: double.infinity,
fit: BoxFit.cover,
@@ -106,14 +106,14 @@ class UpSalesUpgradesWidget extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Text(
- '${roomUpgrade.price} kr.',
+ "total_charge_value"
+ .tr(args: [roomUpgrade.price]),
style: theme.textTheme.headlineMedium,
),
const SizedBox(width: 8),
showCounter
? UpgradesCounter(quantity: quantity)
- : ComwellRadioButton(
- selected: isSelected),
+ : ComwellRadioButton(selected: isSelected),
],
),
],
@@ -122,7 +122,7 @@ class UpSalesUpgradesWidget extends StatelessWidget {
GestureDetector(
onTap: () {
onReadMoreTap(
- context, roomUpgrade, quantity, selectedUpSales);
+ context, roomUpgrade, quantity, selectedUpSales);
},
child: Text(
'read_more_up_sales'.tr(),
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 f1091b6a..588d183d 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
@@ -94,4 +94,14 @@ class UpSalesCubit extends Cubit<UpSalesState> {
.where((element) => element.id == roomUpgrade.id)
.length;
}
+
+ void toggleTermsAccepted() {
+ emit(state.copyWith(termsAccepted: !state.termsAccepted));
+ }
+
+ Future<void> confirmUpSales() async {
+ // Simulate network/API call
+ await Future.delayed(const Duration(seconds: 2));
+ // You can add logic here to update state if needed
+ }
}
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 b71bcd09..0b9cd7ee 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
@@ -8,23 +8,27 @@ class UpSalesState extends Equatable {
final Exception? error;
final bool isLoading;
final int quantity;
- const UpSalesState(
- {required this.selected,
- required this.upSales,
- required this.selectedUpSales,
- this.error,
- required this.isLoading,
- this.quantity = 0});
+ final bool termsAccepted;
+ const UpSalesState({
+ required this.selected,
+ required this.upSales,
+ required this.selectedUpSales,
+ this.error,
+ required this.isLoading,
+ this.quantity = 0,
+ this.termsAccepted = false,
+ });
@override
- List<Object?> get props => [selected, upSales, selectedUpSales, quantity];
+ List<Object?> get props => [selected, upSales, selectedUpSales, quantity, termsAccepted];
UpSalesState.initial({this.quantity = 0})
: selected = false,
upSales = [],
selectedUpSales = [],
error = null,
- isLoading = false;
+ isLoading = false,
+ termsAccepted = false;
UpSalesState setupError({required Exception error}) =>
copyWith(isLoading: false, error: error);
@@ -70,6 +74,7 @@ class UpSalesState extends Equatable {
bool? isLoading,
Exception? error,
int? quantity,
+ bool? termsAccepted,
}) {
return UpSalesState(
selected: selected ?? this.selected,
@@ -78,6 +83,7 @@ class UpSalesState extends Equatable {
isLoading: isLoading ?? this.isLoading,
error: error ?? this.error,
quantity: quantity ?? this.quantity,
+ termsAccepted: termsAccepted ?? this.termsAccepted,
);
}
}
diff --git a/comwell_key_app/lib/up_sales/models/room_facility.dart b/comwell_key_app/lib/up_sales/models/room_facility.dart
index a3ecef3b..6d26bf49 100644
--- a/comwell_key_app/lib/up_sales/models/room_facility.dart
+++ b/comwell_key_app/lib/up_sales/models/room_facility.dart
@@ -8,8 +8,7 @@ class RoomFacility {
String toString() {
return 'RoomFacility(name: $name, icon: $icon)';
}
-
-
+
}
enum FacilityType {
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 e3f0d7b1..2094afe0 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
@@ -74,7 +74,8 @@ class _OtherUpgradePageState extends State<OtherUpgradePage> {
children: [
Text(widget.extra.roomUpgrade.name,
style: theme.textTheme.headlineLarge),
- Text('${widget.extra.roomUpgrade.price} kr.',
+ Text("total_charge_value"
+ .tr(args: [widget.extra.roomUpgrade.price]),
style: theme.textTheme.headlineLarge),
],
),
diff --git a/comwell_key_app/lib/up_sales/pages/up_sale_confirmation_page.dart b/comwell_key_app/lib/up_sales/pages/up_sale_confirmation_page.dart
new file mode 100644
index 00000000..c217731f
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/pages/up_sale_confirmation_page.dart
@@ -0,0 +1,159 @@
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/profile/utils/urls.dart';
+import 'package:comwell_key_app/routing/app_routes.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/up_sales/models/room_upgrade.dart';
+import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:go_router/go_router.dart';
+import 'package:slider_button/slider_button.dart';
+import 'package:url_launcher/url_launcher.dart';
+
+class UpSaleConfirmationPage extends StatelessWidget {
+ final List<RoomUpgrade> selectedUpSales;
+ final int extrasTotalPrice;
+ const UpSaleConfirmationPage(
+ {super.key,
+ required this.selectedUpSales,
+ required this.extrasTotalPrice});
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return BlocBuilder<UpSalesCubit, UpSalesState>(
+ builder: (context, state) {
+ final cubit = context.read<UpSalesCubit>();
+ final upgradesMap = <String, List<RoomUpgrade>>{};
+ for (final upgrade in selectedUpSales) {
+ upgradesMap.putIfAbsent(upgrade.id, () => []).add(upgrade);
+ }
+ return Scaffold(
+ appBar: const ComwellAppBar(),
+ backgroundColor: Colors.white,
+ body: Padding(
+ padding:
+ const EdgeInsets.symmetric(horizontal: 20.0, vertical: 24.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(height: 8),
+ Text(
+ 'Betalingsoversigt',
+ style: theme.textTheme.headlineLarge,
+ ),
+ const SizedBox(height: 32),
+ if (upgradesMap.isEmpty)
+ Text('Ingen tilvalg valgt.',
+ style: theme.textTheme.bodyMedium),
+ if (upgradesMap.isNotEmpty) ...[
+ ListView.separated(
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ separatorBuilder: (_, __) => const SizedBox(height: 8),
+ itemCount: upgradesMap.length,
+ itemBuilder: (context, index) {
+ final upgradeList = upgradesMap.values.elementAt(index);
+ final upgrade = upgradeList.first;
+ final quantity = upgradeList.length;
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Expanded(
+ child: Text(
+ upgrade.name +
+ (quantity > 1 ? ' x$quantity' : ''),
+ style: theme.textTheme.bodyMedium,
+ ),
+ ),
+ Text(
+ (int.tryParse(upgrade.price) != null
+ ? (int.parse(upgrade.price) * quantity)
+ .toString()
+ : upgrade.price),
+ style: theme.textTheme.bodyMedium,
+ ),
+ ],
+ );
+ },
+ ),
+ const Divider(color: colorDivider),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text("total_charge".tr(),
+ style: theme.textTheme.bodyMedium),
+ Text("total_charge_value"
+ .tr(args: [extrasTotalPrice.toString()])),
+ ],
+ ),
+ const SizedBox(height: 16),
+ ],
+ Row(
+ children: [
+ Checkbox(
+ value: state.termsAccepted,
+ onChanged: (_) => cubit.toggleTermsAccepted(),
+ side: const BorderSide(color: colorDivider),
+ visualDensity: VisualDensity.compact,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(4),
+ ),
+ activeColor: sandColor[80],
+ ),
+ Text("approve_conditions_title".tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: colorHeadlineText,
+ )),
+ GestureDetector(
+ onTap: () {
+ // TODO: Whats the correct url?
+ launchUrl(Uri.parse(ComwellUrls.clubRules));
+ },
+ child: Text(
+ 'approve_conditions_subtitle'.tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: sandColor,
+ decoration: TextDecoration.underline,
+ decorationColor: sandColor,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ bottomNavigationBar: Padding(
+ padding:
+ const EdgeInsets.symmetric(horizontal: 16.0, vertical: 24.0),
+ child: SliderButton(
+ backgroundColor: sandColor,
+ disable: !state.termsAccepted,
+ buttonSize: 58,
+ width: double.infinity,
+ icon: Center(
+ child: state.termsAccepted
+ ? const Icon(Icons.chevron_right,
+ size: 32, color: Colors.black)
+ : null,
+ ),
+ action: () async {
+ context.pushNamed(AppRoutes.upSalesAnimation.name, extra: [selectedUpSales, extrasTotalPrice]);
+
+ return true;
+ },
+ label: Center(
+ child: Text("add_to_booking".tr(),
+ style: theme.textTheme.headlineSmall
+ ?.copyWith(color: Colors.white))),
+ ),
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/comwell_key_app/lib/up_sales/pages/up_sales_processing_page.dart b/comwell_key_app/lib/up_sales/pages/up_sales_processing_page.dart
new file mode 100644
index 00000000..cedc0d08
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/pages/up_sales_processing_page.dart
@@ -0,0 +1,85 @@
+import 'package:comwell_key_app/themes/dark_theme.dart';
+import 'package:comwell_key_app/up_sales/cubit/up_sales_cubit.dart';
+import 'package:comwell_key_app/routing/app_routes.dart';
+import 'package:comwell_key_app/utils/lottie_utils.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:go_router/go_router.dart';
+import 'package:lottie/lottie.dart';
+
+class UpSalesProcessingPage extends StatefulWidget {
+ const UpSalesProcessingPage({super.key});
+
+ @override
+ State<UpSalesProcessingPage> createState() => _UpSalesProcessingPageState();
+}
+
+class _UpSalesProcessingPageState extends State<UpSalesProcessingPage>
+ with SingleTickerProviderStateMixin {
+ LottieComposition? loadingComposition;
+ late final AnimationController animationController;
+
+ @override
+ void initState() {
+ animationController = AnimationController(vsync: this);
+ super.initState();
+ _startConfirmation();
+ }
+
+ @override
+ void dispose() {
+ animationController.dispose();
+ super.dispose();
+ }
+
+ void playLoading() {
+ loadingComposition?.playBetween(
+ animationController,
+ "spinner",
+ markerEnd: "success",
+ repeat: true,
+ );
+ }
+
+ void playSuccess() async {
+ await loadingComposition?.playBetween(
+ animationController,
+ "success",
+ markerEnd: "error",
+ );
+ await Future<void>.delayed(const Duration(seconds: 1));
+ if (mounted) context.goNamed(AppRoutes.bookingDetails.name);
+ }
+
+ Future<void> _startConfirmation() async {
+ // Start loading animation
+ playLoading();
+ final cubit = context.read<UpSalesCubit>();
+ await cubit.confirmUpSales();
+ playSuccess();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Container(
+ alignment: Alignment.center,
+ color: sandColor[80],
+ child: Lottie.asset(
+ 'assets/animations/load_animation.json',
+ controller: animationController,
+ onLoaded: (composition) {
+ if (loadingComposition == null) {
+ loadingComposition = composition;
+ animationController.duration = composition.duration;
+ playLoading();
+ }
+ },
+ fit: BoxFit.cover,
+ width: 64,
+ height: 64,
+ ),
+ ),
+ );
+ }
+}
\ No newline at end of file
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 61449b93..bca9c0a0 100644
--- a/comwell_key_app/lib/up_sales/up_sales_catalog.dart
+++ b/comwell_key_app/lib/up_sales/up_sales_catalog.dart
@@ -103,7 +103,7 @@ class UpSalesCatalog extends StatelessWidget {
),
),
const SizedBox(height: 24),
- Padding(
+ Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text('other_up_sales'.tr(),
style: theme.textTheme.headlineMedium),