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

AuthorEdmir Suljic<esu@dwarf.dk>
Date2025-06-18 16:22:57 +0200
Mid feature.

Changed files

comwell_key_app/.fvm/fvm_config.json               |   2 +-
 comwell_key_app/.fvm/release                       |   2 +-
 comwell_key_app/.fvm/version                       |   2 +-
 comwell_key_app/.fvmrc                             |   2 +-
 comwell_key_app/assets/translations/da-DK.json     |   7 +-
 comwell_key_app/assets/translations/en-US.json     |   5 +-
 .../booking_details/bloc/booking_details_bloc.dart |  17 +-
 .../bloc/booking_details_event.dart                |   9 +
 .../bloc/booking_details_state.dart                |  11 +-
 .../components/booking_details_bottom_sheet.dart   |  75 +++---
 .../lib/my_booking/my_booking_page.dart            |   2 +
 comwell_key_app/lib/routing/app_router.dart        |   3 +-
 .../interceptors/response_handle_interceptor.dart  |   3 +-
 .../components/catalog/other_upgrade_catalog.dart  |  42 ++++
 .../components/catalog/room_uprade_catalog.dart    |  43 ++++
 .../components/catalog/service_catalog.dart        |  36 +++
 .../lib/up_sales/components/item_counter.dart      |   9 +-
 .../components/up_sales_services_widget.dart       | 143 ++++++-----
 .../components/up_sales_upgrades_widget.dart       |  42 +++-
 .../lib/up_sales/components/upgrades_counter.dart  |   4 +-
 .../lib/up_sales/cubit/up_sales_cubit.dart         |  55 +++--
 .../lib/up_sales/cubit/up_sales_state.dart         |  36 ++-
 .../lib/up_sales/models/room_upgrade.dart          |   5 +-
 .../lib/up_sales/models/room_upgrade_extra.dart    |   8 +
 .../lib/up_sales/models/room_upgrade_list.dart     |   8 +
 .../lib/up_sales/pages/other_upgrade_page.dart     |  31 +--
 .../lib/up_sales/pages/room_upgrade_page.dart      | 261 +++++++++++----------
 .../lib/up_sales/up_sale_repository.dart           |  44 ++++
 comwell_key_app/lib/up_sales/up_sales_catalog.dart |  43 +++-
 .../test/overview_test/overview_cubic_test.dart    |  16 +-
 .../overview_test/overview_repository_test.dart    |   8 +-
 31 files changed, 653 insertions(+), 321 deletions(-)

Diff

diff --git a/comwell_key_app/.fvm/fvm_config.json b/comwell_key_app/.fvm/fvm_config.json
index 489810e6..41b45a53 100644
--- a/comwell_key_app/.fvm/fvm_config.json
+++ b/comwell_key_app/.fvm/fvm_config.json
@@ -1,3 +1,3 @@
{
- "flutterSdkVersion": "3.24.4"
+ "flutterSdkVersion": "3.27.1"
}
\ No newline at end of file
diff --git a/comwell_key_app/.fvm/release b/comwell_key_app/.fvm/release
index 057aa0d0..b8b1d815 100644
--- a/comwell_key_app/.fvm/release
+++ b/comwell_key_app/.fvm/release
@@ -1 +1 @@
-3.24.4
\ No newline at end of file
+3.27.1
\ No newline at end of file
diff --git a/comwell_key_app/.fvm/version b/comwell_key_app/.fvm/version
index c93df967..b8b1d815 100644
--- a/comwell_key_app/.fvm/version
+++ b/comwell_key_app/.fvm/version
@@ -1 +1 @@
-3.28.0-2.0.pre.38699
\ No newline at end of file
+3.27.1
\ No newline at end of file
diff --git a/comwell_key_app/.fvmrc b/comwell_key_app/.fvmrc
index ff263c64..0fdcb487 100644
--- a/comwell_key_app/.fvmrc
+++ b/comwell_key_app/.fvmrc
@@ -1,3 +1,3 @@
{
- "flutter": "3.24.4"
+ "flutter": "3.27.1"
}
\ No newline at end of file
diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index 7496514f..041480cc 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -29,7 +29,7 @@
"become_cc_member_title": "Bliv medlem af comwell club",
"become_cc_member_subtitle": "Bliv medlem og optjen point, hver gang du overnatter på et Comwell Hotel.",
"overview_tabbar_active": "Aktuelle",
- "overview_tabbar_past": "Tidligere",
+ "overview_tabbar_past": "Tidligere",
"overview_tabbar_cancelled": "Annulleret",
"no_past_bookings_title": "Ingen tidligere ophold",
"no_past_bookings_subtitle": "Du har ingen tidligere overnatninger på Comwell Hotels.",
@@ -277,5 +277,8 @@
"apple_maps": "Apple Kort",
"google_maps": "Google Kort",
"add_to_booking": "Tilføj til booking",
- "see_all_facilities": "Se alle faciliteter"
+ "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 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 8d9edfc2..e4be775d 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -276,6 +276,9 @@
"apple_maps": "Apple Maps",
"google_maps": "Google Maps",
"add_to_booking": "Add to booking",
- "see_all_facilities": "See all facilities"
+ "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"
}
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 544bc723..6730077a 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
@@ -5,6 +5,8 @@ import 'package:comwell_key_app/overview/models/guest.dart';
import 'package:comwell_key_app/profile/profile_repository.dart';
import 'package:comwell_key_app/profile_settings/model/user.dart';
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/utils/seos_repository.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
@@ -27,11 +29,15 @@ class BookingDetailsBloc
final ProfileRepository profileRepository;
final SeosRepository seosRepository = locator<SeosRepository>();
Duration _remainingTime = Duration.zero;
+ final UpSaleRepository upSaleRepository;
+ List<RoomUpgrade> upSales = [];
+
BookingDetailsBloc(
this.booking, {
required this.bookingDetailsRepository,
required this.profileRepository,
+ required this.upSaleRepository,
}) : super(BookingDetailsState.initial(booking)) {
on<InitialEvent>((event, emit) async {
try {
@@ -42,13 +48,17 @@ class BookingDetailsBloc
//add(GetBookingDetailsEvent(booking.confirmationId));
add(GetUserEvent());
add(UpdateRemainingEvent(getCheckInTime().difference(DateTime.now())));
-
+ add(GetUpSalesEvent(upSales));
} catch (e, st) {
if (kDebugMode) print("err=$e, $st");
emit(state.setupError());
}
});
+ on<GetUpSalesEvent>((event, emit) async {
+ await getUpSales(emit);
+ });
+
on<UpdateRemainingEvent>((event, emit) async {
await updateRemainingTime(emit);
});
@@ -75,6 +85,11 @@ class BookingDetailsBloc
});
}
+ Future<void> getUpSales(Emitter<BookingDetailsState> emit) async {
+ upSales = await upSaleRepository.getMockUpSales();
+ emit(state.getUpSales(upSales));
+ }
+
Future<Booking> getBookingDetails(
Emitter<BookingDetailsState> emit, String bookingId) async {
try {
diff --git a/comwell_key_app/lib/booking_details/bloc/booking_details_event.dart b/comwell_key_app/lib/booking_details/bloc/booking_details_event.dart
index 5087319f..2b386a8c 100644
--- a/comwell_key_app/lib/booking_details/bloc/booking_details_event.dart
+++ b/comwell_key_app/lib/booking_details/bloc/booking_details_event.dart
@@ -9,6 +9,15 @@ sealed class BookingDetailsEvent extends Equatable {
final class InitialEvent extends BookingDetailsEvent {}
+final class GetUpSalesEvent extends BookingDetailsEvent {
+ final List<RoomUpgrade> upSales;
+
+ const GetUpSalesEvent(this.upSales);
+
+ @override
+ List<Object> get props => [upSales];
+}
+
final class CheckIfHouseKeepingOrdered extends BookingDetailsEvent {}
final class GetBookingDetailsEvent extends BookingDetailsEvent {
diff --git a/comwell_key_app/lib/booking_details/bloc/booking_details_state.dart b/comwell_key_app/lib/booking_details/bloc/booking_details_state.dart
index 367a979b..54789e66 100644
--- a/comwell_key_app/lib/booking_details/bloc/booking_details_state.dart
+++ b/comwell_key_app/lib/booking_details/bloc/booking_details_state.dart
@@ -8,7 +8,7 @@ class BookingDetailsState extends Equatable {
final Iterable<Guest> guests;
final Duration remainingTime;
final bool isLoading;
-
+ final List<RoomUpgrade> upSales;
const BookingDetailsState._(
{required this.status,
required this.key,
@@ -16,7 +16,8 @@ class BookingDetailsState extends Equatable {
required this.isHouseKeepingOrdered,
required this.guests,
required this.remainingTime,
- required this.isLoading});
+ required this.isLoading,
+ required this.upSales});
BookingDetailsState.initial(Booking booking)
: this._(
@@ -26,7 +27,8 @@ class BookingDetailsState extends Equatable {
isHouseKeepingOrdered: false,
guests: booking.guests,
remainingTime: Duration.zero,
- isLoading: false);
+ isLoading: false,
+ upSales: []);
BookingDetailsState setupError() =>
copyWith(status: BookingDetailsStatus.setupError);
BookingDetailsState updateKeys(List<MobileKeysKey> keys) =>
@@ -39,6 +41,7 @@ class BookingDetailsState extends Equatable {
BookingDetailsState loading() => copyWith(status: BookingDetailsStatus.loading);
BookingDetailsState updateRemainingTime(Duration remainingTime) => copyWith(remainingTime: remainingTime);
BookingDetailsState main() => copyWith(status: BookingDetailsStatus.main);
+ BookingDetailsState getUpSales(List<RoomUpgrade> upSales) => copyWith(upSales: upSales);
@override
List<Object?> get props => [status, guests, isLoading, remainingTime];
@@ -51,6 +54,7 @@ class BookingDetailsState extends Equatable {
Iterable<Guest>? guests,
bool? isLoading,
Duration? remainingTime,
+ List<RoomUpgrade>? upSales,
}) {
return BookingDetailsState._(
status: status ?? this.status,
@@ -61,6 +65,7 @@ class BookingDetailsState extends Equatable {
guests: guests ?? this.guests,
isLoading: isLoading ?? this.isLoading,
remainingTime: remainingTime ?? this.remainingTime,
+ upSales: upSales ?? this.upSales,
);
}
diff --git a/comwell_key_app/lib/booking_details/components/booking_details_bottom_sheet.dart b/comwell_key_app/lib/booking_details/components/booking_details_bottom_sheet.dart
index c26cee53..b74f18e3 100644
--- a/comwell_key_app/lib/booking_details/components/booking_details_bottom_sheet.dart
+++ b/comwell_key_app/lib/booking_details/components/booking_details_bottom_sheet.dart
@@ -6,8 +6,8 @@ import 'package:comwell_key_app/common/components/bottom_sheet_widget.dart';
import 'package:comwell_key_app/common/components/outlined_pill_button.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
+import 'package:comwell_key_app/up_sales/components/catalog/service_catalog.dart';
import 'package:comwell_key_app/up_sales/components/up_sales_catalog_button.dart';
-import 'package:comwell_key_app/up_sales/components/up_sales_services_widget.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
@@ -31,36 +31,7 @@ class BookingDetailsBottomSheet extends StatelessWidget {
const SizedBox(height: 20),
const CheckOutButton(),
const SizedBox(height: 20),
- cubit.booking.reservationStatus == ReservationStatus.checkedin
- ? const UpSalesCatalogButton()
- : Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Text('services'.tr(), style: theme.textTheme.headlineMedium),
- const SizedBox(width: 8),
- OutlinedPillButton(
- text: 'up_sales_see_all'.tr(),
- onTap: () {},
- ),
- ],
- ),
- const SizedBox(height: 16),
- const SingleChildScrollView(
- scrollDirection: Axis.horizontal,
- child: Row(
- children: [
- UpSalesServicesWidget(),
- UpSalesServicesWidget(),
- UpSalesServicesWidget(),
- UpSalesServicesWidget(),
- ],
- ),
- ),
- ],
- ),
+ _buildUpSalesCatalogButton(cubit.booking.reservationStatus, context),
const SizedBox(height: 20),
Text("booking_details_page_practical_information".tr()),
const SizedBox(height: 20),
@@ -104,4 +75,46 @@ class BookingDetailsBottomSheet extends StatelessWidget {
],
);
}
+
+ Widget _buildUpSalesCatalogButton(
+ ReservationStatus reservationStatus, BuildContext context) {
+ switch (reservationStatus) {
+ case ReservationStatus.checkedin:
+ return const UpSalesCatalogButton();
+ case ReservationStatus.newreservation:
+ return _buildServices(context);
+ case ReservationStatus.preregistered:
+ return const SizedBox();
+ case ReservationStatus.cancelled:
+ return const SizedBox();
+ case ReservationStatus.checkedout:
+ return const SizedBox();
+ default:
+ return const SizedBox();
+ }
+ }
+
+ Widget _buildServices(BuildContext context) {
+ final theme = Theme.of(context);
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text('services'.tr(), style: theme.textTheme.headlineMedium),
+ const SizedBox(width: 8),
+ OutlinedPillButton(
+ text: 'up_sales_see_all'.tr(),
+ onTap: () {
+ context.pushNamed(AppRoutes.upSalesCatalog.name);
+ },
+ ),
+ ],
+ ),
+ const SizedBox(height: 16),
+ ServiceCatalog(upSales: cubit.upSales, height: 252),
+ ],
+ );
+ }
}
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 0b6f19f3..2ff6df50 100644
--- a/comwell_key_app/lib/my_booking/my_booking_page.dart
+++ b/comwell_key_app/lib/my_booking/my_booking_page.dart
@@ -7,6 +7,7 @@ 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/utils/locator.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@@ -203,6 +204,7 @@ class MyBookingPage extends StatelessWidget {
booking,
bookingDetailsRepository: locator<BookingDetailsRepository>(),
profileRepository: locator<ProfileRepository>(),
+ upSaleRepository: locator<UpSaleRepository>(),
),
child: ShareButton(
guests: booking.guests,
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index d4ee551f..c8812fd6 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -286,7 +286,8 @@ GoRouter goRouter() {
create: (BuildContext context) => BookingDetailsBloc(booking,
bookingDetailsRepository:
locator<BookingDetailsRepository>(),
- profileRepository: locator<ProfileRepository>()),
+ profileRepository: locator<ProfileRepository>(),
+ upSaleRepository: locator<UpSaleRepository>()),
child: const BookingDetailsPage(),
);
},
diff --git a/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart b/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart
index f2954eb7..6be17bd8 100644
--- a/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart
+++ b/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart
@@ -90,7 +90,8 @@ class ResponseHandleInterceptor extends Interceptor {
} else {
final err = DioException(
requestOptions: response.requestOptions,
- error: 'HTTP request error, status code: ${response.statusCode}');
+ error:
+ 'HTTP request error, status code: ${response.statusCode} - message: ${response.data['detail']}');
handler.next(err);
}
} catch (e) {
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
new file mode 100644
index 00000000..71c22968
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/components/catalog/other_upgrade_catalog.dart
@@ -0,0 +1,42 @@
+import 'package:comwell_key_app/routing/app_routes.dart';
+import 'package:comwell_key_app/up_sales/components/up_sales_upgrades_widget.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';
+
+class OtherUpgradeCatalog extends StatelessWidget {
+ final UpSalesCubit cubit;
+ const OtherUpgradeCatalog({super.key, required this.cubit});
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ final otherUpSales = cubit.upSales
+ .where((roomUpgrade) => roomUpgrade.type == UpgradeType.other)
+ .toList();
+
+ if (otherUpSales.isEmpty) {
+ return Text('no_room_upgrades_available'.tr(),
+ style: theme.textTheme.headlineMedium);
+ }
+
+ return SizedBox(
+ height: 289,
+ child: ListView.builder(
+ scrollDirection: Axis.horizontal,
+ itemCount: otherUpSales.length,
+ itemBuilder: (context, index) {
+ return UpSalesUpgradesWidget(
+ width: 328,
+ height: 268,
+ roomUpgrade: otherUpSales.elementAt(index),
+ isSelected: cubit.state.selected,
+ routeName: AppRoutes.otherUpgrade.name,
+ showCounter: true,
+ );
+ },
+ ),
+ );
+ }
+}
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
new file mode 100644
index 00000000..a8f407ff
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/components/catalog/room_uprade_catalog.dart
@@ -0,0 +1,43 @@
+import 'package:comwell_key_app/routing/app_routes.dart';
+import 'package:comwell_key_app/up_sales/components/up_sales_upgrades_widget.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';
+
+class RoomUpgradeCatalog extends StatelessWidget {
+ final UpSalesCubit cubit;
+ const RoomUpgradeCatalog({super.key, required this.cubit});
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ final roomUpSales = cubit.upSales
+ .where((roomUpgrade) => roomUpgrade.type == UpgradeType.room)
+ .toList();
+
+ if (roomUpSales.isEmpty) {
+ return Text('no_room_upgrades_available'.tr(),
+ style: theme.textTheme.headlineMedium);
+ }
+
+ return SizedBox(
+ height: 289,
+ child: ListView.builder(
+ scrollDirection: Axis.horizontal,
+ itemCount: roomUpSales.length,
+ itemBuilder: (context, index) {
+ return UpSalesUpgradesWidget(
+ width: 328,
+ height: 268,
+ roomUpgrade: roomUpSales.elementAt(index),
+ isSelected: cubit.state.selected,
+ routeName: AppRoutes.roomUpgrade.name,
+ showCounter: false,
+ );
+ },
+ ),
+ );
+
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 00000000..fe0d3257
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/components/catalog/service_catalog.dart
@@ -0,0 +1,36 @@
+import 'package:comwell_key_app/up_sales/components/up_sales_services_widget.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';
+
+class ServiceCatalog extends StatelessWidget {
+ final List<RoomUpgrade> upSales;
+ final double? height;
+ const ServiceCatalog({super.key, required this.upSales, this.height});
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ final services = upSales
+ .where((roomUpgrade) => roomUpgrade.type == UpgradeType.service)
+ .toList();
+
+
+ if (services.isEmpty) {
+ return Text('no_services_available'.tr(), style: theme.textTheme.headlineMedium);
+ }
+
+ return SizedBox(
+ height: height ?? 180,
+ child: ListView.builder(
+ scrollDirection: Axis.horizontal,
+ itemCount: services.length,
+ itemBuilder: (context, index) {
+ final isPopular = services.elementAt(index).tags.contains('popular');
+ return UpSalesServicesWidget(width: 328, roomUpgrade: services.elementAt(index), isPopular: isPopular);
+ },
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/up_sales/components/item_counter.dart b/comwell_key_app/lib/up_sales/components/item_counter.dart
index 6eb99b03..1e560c03 100644
--- a/comwell_key_app/lib/up_sales/components/item_counter.dart
+++ b/comwell_key_app/lib/up_sales/components/item_counter.dart
@@ -1,19 +1,20 @@
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/up_sales/models/room_upgrade_extra.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ItemCounter extends StatelessWidget {
- final int quantity;
- final Function(int) onQuantityChanged;
-
- const ItemCounter({super.key, required this.quantity, required this.onQuantityChanged});
+ final RoomUpgradeExtra extra;
+ const ItemCounter({super.key, required this.extra});
@override
Widget build(BuildContext context) {
return BlocBuilder<UpSalesCubit, UpSalesState>(builder: (context, state) {
final theme = Theme.of(context);
final cubit = context.read<UpSalesCubit>();
+
return Container(
color: Colors.white,
child: Padding(
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 d7187bbf..d6140182 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
@@ -4,6 +4,7 @@ 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/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/up_sales/up_sale_repository.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@@ -12,80 +13,92 @@ import 'package:flutter_bloc/flutter_bloc.dart';
class UpSalesServicesWidget extends StatelessWidget {
final double width;
final double height;
- const UpSalesServicesWidget({super.key, this.width = 328, this.height = 252});
+ final RoomUpgrade roomUpgrade;
+ final bool? isSelected;
+ final bool? isPopular;
+ const UpSalesServicesWidget(
+ {super.key,
+ this.width = 328,
+ this.height = 252,
+ required this.roomUpgrade,
+ this.isSelected,
+ this.isPopular});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- return BlocProvider(
- create: (context) => UpSalesCubit(upSaleRepository: UpSaleRepository()),
- child: BlocBuilder<UpSalesCubit, UpSalesState>(builder: (context, state) {
- final cubit = context.read<UpSalesCubit>();
- return Container(
- width: width,
- height: height,
- 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('early_checkin'.tr(),
- style: theme.textTheme.headlineMedium),
- ],
- ),
- ),
- Column(
- crossAxisAlignment: CrossAxisAlignment.end,
+ return Container(
+ width: width,
+ height: height,
+ 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: [
- Row(
- children: [
- Text(
- '200 kr.',
- style: theme.textTheme.headlineMedium,
- ),
- const SizedBox(width: 8),
- ComwellRadioButton(selected: cubit.state.selected, onTap: () {}),
- ],
- ),
+ Text(roomUpgrade.name,
+ style: theme.textTheme.headlineMedium),
],
),
- ],
- ),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- const TagWidget(text: 'POPULÆR'),
- const SizedBox(height: 8),
- Container(
- width: 250,
- child: Text(
- 'Med tidlig check-in kan du checke ind kl. 13.00 i stedet for kl. 15.00.',
- style: theme.textTheme.bodySmall?.copyWith(
- color: colorHeadlineText,
- ),
- maxLines: 2,
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Row(
+ children: [
+ Text(
+ '${roomUpgrade.price} kr.',
+ style: theme.textTheme.headlineMedium,
+ ),
+ const SizedBox(width: 8),
+ ComwellRadioButton(
+ selected: isSelected ?? false,
+ onTap: () {
+ // if (isSelected) {
+ // cubit.removeUpgrade(roomUpgrade);
+ // } else {
+ // cubit.addSelected(roomUpgrade);
+ // }
+ }),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ if (isPopular!) TagWidget(text: roomUpgrade.tags.first.toUpperCase()),
+ const SizedBox(height: 8),
+ SizedBox(
+ width: 250,
+ child: Text(
+ roomUpgrade.description,
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: colorHeadlineText,
),
+ maxLines: 2,
),
- ],
- ),
- ],
- ),
- );
- }),
- );
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+
}
}
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 54d1220f..8263f63b 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
@@ -4,6 +4,8 @@ import 'package:comwell_key_app/up_sales/components/upgrades_counter.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/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';
@@ -31,13 +33,13 @@ class UpSalesUpgradesWidget extends StatelessWidget {
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
.where((element) => element.id == roomUpgrade.id)
.length;
- print("quantity ${quantity}");
return Container(
width: width,
height: height,
@@ -58,7 +60,7 @@ class UpSalesUpgradesWidget extends StatelessWidget {
topRight: Radius.circular(10),
),
child: Image.asset(
- roomUpgrade.images.first,
+ roomUpgrade.images!.first,
height: 180,
width: double.infinity,
fit: BoxFit.cover,
@@ -116,10 +118,7 @@ class UpSalesUpgradesWidget extends StatelessWidget {
showCounter
? UpgradesCounter(quantity: quantity)
: ComwellRadioButton(
- selected: isSelected,
- onTap: () => cubit
- .toggleSelected(roomUpgrade.id),
- ),
+ selected: isSelected, onTap: () {}),
],
),
],
@@ -127,12 +126,31 @@ class UpSalesUpgradesWidget extends StatelessWidget {
const SizedBox(height: 8),
GestureDetector(
onTap: () async {
- final roomUpgradeResponse = await context.pushNamed(routeName, extra: roomUpgrade);
- if (roomUpgradeResponse is RoomUpgrade) {
- print("response ${roomUpgradeResponse.id}");
- cubit.addSelected(roomUpgradeResponse);
- } else if (roomUpgradeResponse is int) {
- cubit.addOtherUpgradeWithQuantity(roomUpgrade, roomUpgradeResponse);
+ 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(
diff --git a/comwell_key_app/lib/up_sales/components/upgrades_counter.dart b/comwell_key_app/lib/up_sales/components/upgrades_counter.dart
index 63c6e91d..004f6b89 100644
--- a/comwell_key_app/lib/up_sales/components/upgrades_counter.dart
+++ b/comwell_key_app/lib/up_sales/components/upgrades_counter.dart
@@ -12,11 +12,11 @@ class UpgradesCounter extends StatelessWidget {
width: 24,
height: 24,
decoration: BoxDecoration(
- color: quantity > 1 ? Colors.black : Colors.transparent ,
+ color: quantity > 0 ? Colors.black : Colors.transparent ,
shape: BoxShape.circle,
border: Border.all(color: colorDivider, width: 1.5),
),
- child: quantity > 1 ? Center(
+ child: quantity > 0 ? Center(
child: Text(quantity.toString(), style: theme.textTheme.headlineSmall?.copyWith(color: Colors.white, fontSize: 11)),
) : const SizedBox.shrink(),
);
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 0583baf8..637f3e7c 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
@@ -1,17 +1,22 @@
import 'package:bloc/bloc.dart';
import 'package:comwell_key_app/up_sales/cubit/up_sales_state.dart';
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';
class UpSalesCubit extends Cubit<UpSalesState> {
final UpSaleRepository upSaleRepository;
List<RoomUpgrade> upSales = [];
- List<RoomUpgrade> selectedUpSales = [];
+ late RoomUpgradeExtra extra;
UpSalesCubit({required this.upSaleRepository})
: super(UpSalesState.initial());
+ UpSalesCubit.withExtra({required this.upSaleRepository, required this.extra})
+ : super(UpSalesState.initial(quantity: extra.quantity));
+
void toggleSelected(String index) {
emit(state.copyWith(
selected: !state.selected, quantity: state.quantity, upSales: upSales));
@@ -21,11 +26,12 @@ class UpSalesCubit extends Cubit<UpSalesState> {
emit(UpSalesState(
selected: false,
upSales: upSales,
- selectedUpSales: selectedUpSales,
+ selectedUpSales: [],
isLoading: true,
error: null));
try {
upSales = await upSaleRepository.getMockUpSales();
+
emit(state.loaded(upSales: upSales));
} catch (e) {
emit(state.setupError(error: Error()));
@@ -33,9 +39,18 @@ class UpSalesCubit extends Cubit<UpSalesState> {
}
void addSelected(RoomUpgrade roomUpgrade) {
- print("roomUpgrade ${roomUpgrade.id}");
- emit(state.addSelected(roomUpgrade: roomUpgrade));
- print("state.selectedUpSales ${state.selectedUpSales.length}");
+ // 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.updateSelectedUpSales(
+ roomUpgradeList: [...filteredUpSales, roomUpgrade]));
+ } else {
+ // For non-room upgrades, just add to the list
+ emit(state.addSelectedUpsales(roomUpgrade: roomUpgrade));
+ }
}
void increment() {
@@ -43,7 +58,7 @@ class UpSalesCubit extends Cubit<UpSalesState> {
}
void decrement() {
- if (state.quantity > 0) {
+ if (extra.quantity > 0 && state.quantity > 0) {
emit(state.removeQuantity());
}
}
@@ -52,23 +67,23 @@ class UpSalesCubit extends Cubit<UpSalesState> {
emit(state.copyWith(selected: false));
}
- void addOtherUpgradeWithQuantity(RoomUpgrade roomUpgrade, int quantity) {
- final updatedSelectedUpSales = List<RoomUpgrade>.from(state.selectedUpSales);
-
- for (int i = 0; i < quantity; i++) {
- updatedSelectedUpSales.add(roomUpgrade);
+ 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.updateSelectedUpSales(roomUpgradeList: filteredUpSales));
+ return;
+ } else {
+ final newSelectedUpSales = List.generate(quantity, (_) => roomUpgrade);
+ emit(state.updateOtherUpgradeWithQuantity(
+ roomUpgradeList: newSelectedUpSales));
}
-
- print("updatedSelectedUpSales ${updatedSelectedUpSales.length}");
- emit(state.addSelected(roomUpgrade: roomUpgrade));
}
void removeUpgrade(RoomUpgrade roomUpgrade) {
- final updatedSelectedUpSales = List<RoomUpgrade>.from(state.selectedUpSales);
- updatedSelectedUpSales.remove(roomUpgrade);
-
- emit(state.copyWith(
- selectedUpSales: updatedSelectedUpSales,
- ));
+ emit(state.removeSelectedUpSales(roomUpgrade: roomUpgrade));
+ print("length: ${state.selectedUpSales.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 4540003c..08e675c9 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
@@ -19,21 +19,45 @@ class UpSalesState extends Equatable {
@override
List<Object?> get props => [selected, upSales, selectedUpSales, quantity];
- UpSalesState.initial()
+ UpSalesState.initial({this.quantity = 0})
: selected = false,
upSales = [],
selectedUpSales = [],
error = null,
- isLoading = false,
- quantity = 0;
+ isLoading = false;
- UpSalesState setupError({required Error error}) => copyWith(isLoading: false, error: error);
+ UpSalesState setupError({required Error error}) =>
+ copyWith(isLoading: false, error: error);
UpSalesState loading() => copyWith(isLoading: true);
- UpSalesState loaded({required List<RoomUpgrade> upSales}) => copyWith(isLoading: false, upSales: upSales);
+ UpSalesState loaded({required List<RoomUpgrade> upSales}) =>
+ copyWith(isLoading: false, upSales: upSales);
- UpSalesState addSelected({required RoomUpgrade roomUpgrade}) => copyWith(selectedUpSales: [...selectedUpSales, roomUpgrade]);
+ UpSalesState addSelectedUpsales({required RoomUpgrade roomUpgrade}) =>
+ copyWith(selectedUpSales: [...selectedUpSales, roomUpgrade]);
+
+ UpSalesState updateSelectedUpSales({required List<RoomUpgrade> roomUpgradeList}) =>
+ copyWith(selectedUpSales: roomUpgradeList);
+
+ UpSalesState updateOtherUpgradeWithQuantity(
+ {required List<RoomUpgrade> roomUpgradeList}) {
+ if (roomUpgradeList.isEmpty) return this;
+
+ // Get the ID of the item we're updating
+ final String updateItemId = roomUpgradeList.first.id;
+
+ // Remove existing items with the same ID
+ final existingItems = selectedUpSales
+ .where((upgrade) => upgrade.id != updateItemId)
+ .toList();
+
+ // Add the new items while preserving other items
+ return copyWith(selectedUpSales: [...existingItems, ...roomUpgradeList]);
+ }
+
+ UpSalesState removeSelectedUpSales({required RoomUpgrade roomUpgrade}) =>
+ copyWith(selectedUpSales: selectedUpSales.where((upgrade) => upgrade.id != roomUpgrade.id).toList());
UpSalesState addQuantity() => copyWith(quantity: quantity + 1);
diff --git a/comwell_key_app/lib/up_sales/models/room_upgrade.dart b/comwell_key_app/lib/up_sales/models/room_upgrade.dart
index a3b5a047..96bbc457 100644
--- a/comwell_key_app/lib/up_sales/models/room_upgrade.dart
+++ b/comwell_key_app/lib/up_sales/models/room_upgrade.dart
@@ -3,11 +3,11 @@ import 'package:comwell_key_app/up_sales/models/room_facility.dart';
class RoomUpgrade {
final String name;
final String price;
- final Iterable<String> images;
+ final Iterable<String>? images;
final String description;
final String id;
final Iterable<String> tags;
- final Iterable<RoomFacility> facilities;
+ final Iterable<RoomFacility>? facilities;
final UpgradeType type;
RoomUpgrade(
{required this.name,
@@ -52,6 +52,7 @@ class RoomUpgrade {
}
enum UpgradeType {
+ service,
room,
other;
diff --git a/comwell_key_app/lib/up_sales/models/room_upgrade_extra.dart b/comwell_key_app/lib/up_sales/models/room_upgrade_extra.dart
new file mode 100644
index 00000000..7ee4b2d5
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/models/room_upgrade_extra.dart
@@ -0,0 +1,8 @@
+import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
+
+class RoomUpgradeExtra {
+ final RoomUpgrade roomUpgrade;
+ int quantity = 0;
+
+ RoomUpgradeExtra({required this.roomUpgrade, required this.quantity});
+}
diff --git a/comwell_key_app/lib/up_sales/models/room_upgrade_list.dart b/comwell_key_app/lib/up_sales/models/room_upgrade_list.dart
new file mode 100644
index 00000000..b0561461
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/models/room_upgrade_list.dart
@@ -0,0 +1,8 @@
+import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
+
+class RoomUpgradeList {
+ final RoomUpgrade roomUpgrade;
+ final List<RoomUpgrade> roomUpgrades;
+
+ RoomUpgradeList({required this.roomUpgrade, required this.roomUpgrades});
+}
\ No newline at end of file
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 1296bb60..3bb28259 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
@@ -2,6 +2,7 @@ import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
import 'package:comwell_key_app/up_sales/components/item_counter.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:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -10,15 +11,15 @@ import '../../themes/light_theme.dart';
import '../components/up_sales_bottom_button.dart';
class OtherUpgradePage extends StatefulWidget {
- final RoomUpgrade roomUpgrade;
- const OtherUpgradePage({super.key, required this.roomUpgrade});
+ final RoomUpgradeExtra extra;
+ const OtherUpgradePage({super.key, required this.extra});
@override
State<OtherUpgradePage> createState() => _OtherUpgradePageState();
}
class _OtherUpgradePageState extends State<OtherUpgradePage> {
- int _quantity = 1;
+
@override
Widget build(BuildContext context) {
@@ -42,7 +43,7 @@ class _OtherUpgradePageState extends State<OtherUpgradePage> {
topRight: Radius.circular(10),
),
child: Image.asset(
- widget.roomUpgrade.images.first,
+ widget.extra.roomUpgrade.images!.first,
height: height * 0.5,
width: double.infinity,
fit: BoxFit.cover,
@@ -73,17 +74,17 @@ class _OtherUpgradePageState extends State<OtherUpgradePage> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Text(widget.roomUpgrade.name,
+ Text(widget.extra.roomUpgrade.name,
style: theme.textTheme.headlineLarge),
- Text('${widget.roomUpgrade.price} kr.',
+ Text('${widget.extra.roomUpgrade.price} kr.',
style: theme.textTheme.headlineLarge),
],
),
const SizedBox(height: 12),
- Container(
+ SizedBox(
width: width * 0.8,
child: Text(
- widget.roomUpgrade.description,
+ widget.extra.roomUpgrade.description,
style: theme.textTheme.bodySmall
?.copyWith(color: colorHeadlineText),
),
@@ -103,20 +104,12 @@ class _OtherUpgradePageState extends State<OtherUpgradePage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
- ItemCounter(
- quantity: _quantity,
- onQuantityChanged: (newQuantity) {
- setState(() {
- _quantity = newQuantity;
- });
- },
- ),
+ ItemCounter(extra: widget.extra),
Expanded(
flex: 2,
child: UpSalesBottomButton(
- onContinue: () {
- cubit.addOtherUpgradeWithQuantity(widget.roomUpgrade, _quantity);
- Navigator.pop(context, widget.roomUpgrade);
+ onContinue: () {
+ Navigator.pop(context, cubit.state.quantity);
},
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 72f095a7..f03cdb38 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
@@ -7,6 +7,7 @@ import 'package:comwell_key_app/up_sales/components/room_image_carousel.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/up_sales/models/room_upgrade_list.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
@@ -16,8 +17,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
class RoomUpgradePage extends StatefulWidget {
- final RoomUpgrade roomUpgrade;
- const RoomUpgradePage({super.key, required this.roomUpgrade});
+ final RoomUpgradeList roomUpgradeList;
+ const RoomUpgradePage({super.key, required this.roomUpgradeList});
@override
State<RoomUpgradePage> createState() => _RoomUpgradePageState();
@@ -25,145 +26,153 @@ class RoomUpgradePage extends StatefulWidget {
class _RoomUpgradePageState extends State<RoomUpgradePage> {
bool _isExpanded = false;
-
- List<RoomFacility> get allFacilities => [
- ...widget.roomUpgrade.facilities,
- // Optionally add more facilities if needed, or fetch from a global list
- ];
+ List<RoomFacility> get allFacilities => [...widget.roomUpgradeList.roomUpgrade.facilities!];
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- final cubit = context.read<UpSalesCubit>();
+ final isSelected = widget.roomUpgradeList.roomUpgrades.contains(widget.roomUpgradeList.roomUpgrade);
+
+ return BlocBuilder<UpSalesCubit, UpSalesState>(builder: (context, state) {
- return BlocBuilder<UpSalesCubit, UpSalesState>(
- builder: (context, state) {
- return Scaffold(
- extendBodyBehindAppBar: true,
- appBar: const ComwellAppBar(),
- backgroundColor: Colors.white,
- body: SingleChildScrollView(
- physics: const AlwaysScrollableScrollPhysics(),
- child: ConstrainedBox(
- constraints: BoxConstraints(
- minHeight: MediaQuery.of(context).size.height -
- kComwellAppBarHeight -
- 80, // 80 is approximate height of bottom button
- ),
- child: Column(
- children: [
- RoomImageCarousel(images: widget.roomUpgrade.images.toList()),
- Container(
- width: double.infinity,
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(24),
- topRight: Radius.circular(24),
- ),
+ return Scaffold(
+ extendBodyBehindAppBar: true,
+ appBar: const ComwellAppBar(),
+ backgroundColor: Colors.white,
+ body: SingleChildScrollView(
+ physics: const AlwaysScrollableScrollPhysics(),
+ child: ConstrainedBox(
+ constraints: BoxConstraints(
+ minHeight: MediaQuery.of(context).size.height -
+ kComwellAppBarHeight -
+ 80,
+ ),
+ child: Column(
+ children: [
+ RoomImageCarousel(images: widget.roomUpgradeList.roomUpgrade.images!.toList()),
+ Container(
+ width: double.infinity,
+ decoration: const BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(24),
+ topRight: Radius.circular(24),
),
- child: Padding(
- padding:
- const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- mainAxisSize: MainAxisSize.min,
- children: [
- Text(
- widget.roomUpgrade.name,
- style: theme.textTheme.headlineLarge,
- ),
- const SizedBox(width: 12),
- if (widget.roomUpgrade.tags.isNotEmpty)
- TagWidget(
- text: '${widget.roomUpgrade.tags.first} M2',
- textColor: sandColor),
- ],
- ),
- const SizedBox(height: 12),
- Text(
- widget.roomUpgrade.description,
- style: theme.textTheme.bodySmall,
- maxLines: _isExpanded ? null : 3,
- overflow: _isExpanded ? null : TextOverflow.ellipsis,
- ),
- const SizedBox(height: 4),
- GestureDetector(
- onTap: () {
- setState(() {
- _isExpanded = !_isExpanded;
- });
- },
- child: Text(
- _isExpanded ? 'read_less'.tr() : 'read_more'.tr(),
- style: theme.textTheme.bodySmall?.copyWith(
- color: sandColor,
- decoration: TextDecoration.underline,
- decorationColor: sandColor,
- ),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 24, vertical: 16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ widget.roomUpgradeList.roomUpgrade.name,
+ style: theme.textTheme.headlineLarge,
+ ),
+ const SizedBox(width: 12),
+ if (widget.roomUpgradeList.roomUpgrade.tags.isNotEmpty)
+ TagWidget(
+ text: '${widget.roomUpgradeList.roomUpgrade.tags.first} M2',
+ textColor: sandColor),
+ ],
+ ),
+ const SizedBox(height: 12),
+ Text(
+ widget.roomUpgradeList.roomUpgrade.description,
+ style: theme.textTheme.bodySmall,
+ maxLines: _isExpanded ? null : 3,
+ overflow: _isExpanded ? null : TextOverflow.ellipsis,
+ ),
+ const SizedBox(height: 4),
+ GestureDetector(
+ onTap: () {
+ setState(() {
+ _isExpanded = !_isExpanded;
+ });
+ },
+ child: Text(
+ _isExpanded ? 'read_less'.tr() : 'read_more'.tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: sandColor,
+ decoration: TextDecoration.underline,
+ decorationColor: sandColor,
),
),
- const SizedBox(height: 24),
- // Facilities row
- Wrap(
- spacing: 8,
- runSpacing: 8,
- children: [
- ...widget.roomUpgrade.facilities.map((f) =>
- FacilityIconText(facility: f, showDivider: true)),
- GestureDetector(
- onTap: () => _showFacilitiesSheet(context),
- child: Padding(
- padding:
- const EdgeInsets.symmetric(horizontal: 4.0),
- child: Text(
- 'see_all_facilities'.tr(),
- style: theme.textTheme.bodySmall?.copyWith(
- color: sandColor,
- decoration: TextDecoration.underline,
- decorationColor: sandColor,
- ),
+ ),
+ const SizedBox(height: 24),
+ // Facilities row
+ Wrap(
+ spacing: 8,
+ runSpacing: 8,
+ children: [
+ ...widget.roomUpgradeList.roomUpgrade.facilities!.map((f) =>
+ FacilityIconText(
+ facility: f, showDivider: true)),
+ GestureDetector(
+ onTap: () => _showFacilitiesSheet(context),
+ child: Padding(
+ padding:
+ const EdgeInsets.symmetric(horizontal: 4.0),
+ child: Text(
+ 'see_all_facilities'.tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: sandColor,
+ decoration: TextDecoration.underline,
+ decorationColor: sandColor,
),
),
),
- ],
- ),
- const SizedBox(height: 32),
- ],
- ),
+ ),
+ ],
+ ),
+ const SizedBox(height: 32),
+ ],
),
),
- // Booking button
- ],
- ),
- ),
- ),
- bottomNavigationBar: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- const Divider(color: colorDivider),
- UpSalesBottomButton(onContinue: () {
- Navigator.pop(context, widget.roomUpgrade);
- }, children: [
- Text(
- "add_to_booking".tr(),
- style:
- theme.textTheme.headlineSmall?.copyWith(color: Colors.white),
- ),
- Text(
- "+${widget.roomUpgrade.price} kr.",
- style:
- theme.textTheme.headlineSmall?.copyWith(color: Colors.white),
),
- ]),
- ],
+ // Booking button
+ ],
+ ),
),
- );
- }
- );
+ ),
+ bottomNavigationBar: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const Divider(color: colorDivider),
+ UpSalesBottomButton(
+ onContinue: () {
+ Navigator.pop(context, [widget.roomUpgradeList.roomUpgrade, isSelected]);
+ },
+ children: [
+ isSelected
+ ? Text(
+ "remove_from_booking".tr(),
+ style: theme.textTheme.headlineSmall
+ ?.copyWith(color: Colors.white),
+ )
+ : Text(
+ "add_to_booking".tr(),
+ style: theme.textTheme.headlineSmall
+ ?.copyWith(color: Colors.white),
+ ),
+ isSelected ? Text(
+ " -${widget.roomUpgradeList.roomUpgrade.price} kr.",
+ style: theme.textTheme.headlineSmall
+ ?.copyWith(color: Colors.white),
+ ) : Text(
+ " +${widget.roomUpgradeList.roomUpgrade.price} kr.",
+ style: theme.textTheme.headlineSmall
+ ?.copyWith(color: Colors.white),
+ ),
+ ]),
+ ],
+ ),
+ );
+ });
}
void _showFacilitiesSheet(BuildContext context) {
diff --git a/comwell_key_app/lib/up_sales/up_sale_repository.dart b/comwell_key_app/lib/up_sales/up_sale_repository.dart
index cb30b7bd..aba631d2 100644
--- a/comwell_key_app/lib/up_sales/up_sale_repository.dart
+++ b/comwell_key_app/lib/up_sales/up_sale_repository.dart
@@ -325,4 +325,48 @@ final List<RoomUpgradeDTO> mockRoomUpgrades = [
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 2c5de1d4..b6b28f29 100644
--- a/comwell_key_app/lib/up_sales/up_sales_catalog.dart
+++ b/comwell_key_app/lib/up_sales/up_sales_catalog.dart
@@ -1,5 +1,8 @@
import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
import 'package:comwell_key_app/routing/app_routes.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/components/up_sales_services_widget.dart';
import 'package:comwell_key_app/up_sales/components/up_sales_upgrades_widget.dart';
@@ -20,8 +23,6 @@ class UpSalesCatalog extends StatelessWidget {
return BlocBuilder<UpSalesCubit, UpSalesState>(builder: (context, state) {
final cubit = context.read<UpSalesCubit>();
- print("state.selectedUpSales ${state.selectedUpSales.length}");
-
if (state.isLoading) {
return const Scaffold(
appBar: ComwellAppBar(),
@@ -58,7 +59,7 @@ class UpSalesCatalog extends StatelessWidget {
style: theme.textTheme.headlineMedium),
),
const SizedBox(height: 8),
- _buildServicesCatalog(context, cubit),
+ ServiceCatalog(upSales: cubit.upSales),
const SizedBox(height: 24),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
@@ -66,7 +67,7 @@ class UpSalesCatalog extends StatelessWidget {
style: theme.textTheme.headlineMedium),
),
const SizedBox(height: 8),
- _buildRoomUpgradeCatalog(context, cubit),
+ RoomUpgradeCatalog(cubit: cubit),
const SizedBox(height: 24),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
@@ -74,7 +75,7 @@ class UpSalesCatalog extends StatelessWidget {
style: theme.textTheme.headlineMedium),
),
const SizedBox(height: 8),
- _buildOtherUpSalesCatalog(context, cubit),
+ OtherUpgradeCatalog(cubit: cubit),
const SizedBox(height: 24),
],
),
@@ -97,25 +98,44 @@ class UpSalesCatalog extends StatelessWidget {
}
Widget _buildServicesCatalog(BuildContext context, UpSalesCubit cubit) {
+ final theme = Theme.of(context);
+ final services = cubit.upSales
+ .where((roomUpgrade) => roomUpgrade.type == UpgradeType.service)
+ .toList();
+
+
+ if (services.isEmpty) {
+ return Text('no_services_available'.tr(), style: theme.textTheme.headlineMedium);
+ }
+
+
+
return SizedBox(
- height: 180, // Height of the UpSalesServicesWidget
+ height: 180,
child: ListView.builder(
scrollDirection: Axis.horizontal,
- itemCount: cubit.upSales.length,
+ itemCount: services.length,
itemBuilder: (context, index) {
- return UpSalesServicesWidget(width: 328);
+ final isSelected = cubit.state.selectedUpSales.contains(services.elementAt(index));
+ final isPopular = services.elementAt(index).tags.contains('popular');
+ return UpSalesServicesWidget(width: 328, roomUpgrade: services.elementAt(index), isSelected: isSelected, isPopular: isPopular);
},
),
);
}
Widget _buildRoomUpgradeCatalog(BuildContext context, UpSalesCubit cubit) {
+ final theme = Theme.of(context);
final roomUpSales = cubit.upSales
.where((roomUpgrade) => roomUpgrade.type == UpgradeType.room)
.toList();
+ if (roomUpSales.isEmpty) {
+ return Text('no_room_upgrades_available'.tr(), style: theme.textTheme.headlineMedium);
+ }
+
return SizedBox(
- height: 289, // Height of the UpSalesUpgradesWidget
+ height: 289,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: roomUpSales.length,
@@ -134,10 +154,15 @@ class UpSalesCatalog extends StatelessWidget {
}
Widget _buildOtherUpSalesCatalog(BuildContext context, UpSalesCubit cubit) {
+ final theme = Theme.of(context);
final otherUpSales = cubit.upSales
.where((roomUpgrade) => roomUpgrade.type == UpgradeType.other)
.toList();
+ if (otherUpSales.isEmpty) {
+ return Text('no_room_upgrades_available'.tr(), style: theme.textTheme.headlineMedium);
+ }
+
return SizedBox(
height: 289,
child: ListView.builder(
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 655eb146..23499d3f 100644
--- a/comwell_key_app/test/overview_test/overview_cubic_test.dart
+++ b/comwell_key_app/test/overview_test/overview_cubic_test.dart
@@ -31,7 +31,7 @@ void main() {
current: [
Booking(
id: '1',
- status: BookingStatus.current,
+ bookingStatus: BookingStatus.current,
confirmationId: "s",
roomNumber: '',
startDate: DateTime(2021, 10, 10),
@@ -46,7 +46,7 @@ void main() {
bookingDate: DateTime(2021, 10, 10),
digitalCard: true,
totalCharge: 100,
- reservationStatus: ReservationStatus.newreservation,
+ status: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890")
],
@@ -63,7 +63,7 @@ void main() {
current: [
Booking(
id: '1',
- status: BookingStatus.current,
+ bookingStatus: BookingStatus.current,
roomNumber: '',
startDate: DateTime(2021, 10, 10),
endDate: DateTime(2021, 10, 10),
@@ -78,7 +78,7 @@ void main() {
bookingDate: DateTime(2021, 10, 10),
digitalCard: true,
totalCharge: 100,
- reservationStatus: ReservationStatus.newreservation,
+ status: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890")
],
@@ -117,7 +117,7 @@ void main() {
),
act: (cubit) => cubit.addBooking(Booking(
id: '1',
- status: BookingStatus.current,
+ bookingStatus: BookingStatus.current,
roomNumber: '',
startDate: DateTime(2021, 10, 10),
endDate: DateTime(2021, 10, 10),
@@ -132,7 +132,7 @@ void main() {
bookingDate: DateTime(2021, 10, 10),
digitalCard: true,
totalCharge: 100,
- reservationStatus: ReservationStatus.newreservation,
+ status: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890")),
expect: () => [
@@ -141,7 +141,7 @@ void main() {
current: [
Booking(
id: '1',
- status: BookingStatus.current,
+ bookingStatus: BookingStatus.current,
roomNumber: '',
startDate: DateTime(2021, 10, 10),
endDate: DateTime(2021, 10, 10),
@@ -156,7 +156,7 @@ void main() {
bookingDate: DateTime(2021, 10, 10),
digitalCard: true,
totalCharge: 100,
- reservationStatus: ReservationStatus.newreservation,
+ status: 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 5d6a5726..74fed1cb 100644
--- a/comwell_key_app/test/overview_test/overview_repository_test.dart
+++ b/comwell_key_app/test/overview_test/overview_repository_test.dart
@@ -21,7 +21,7 @@ void main() {
current: [
Booking(
id: '1',
- status: BookingStatus.current,
+ bookingStatus: BookingStatus.current,
roomNumber: '101',
startDate: DateTime.now(),
endDate: DateTime.now().add(const Duration(days: 1)),
@@ -36,7 +36,7 @@ void main() {
bookingDate: DateTime.now(),
digitalCard: true,
totalCharge: 100,
- reservationStatus: ReservationStatus.newreservation,
+ status: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890"
),
@@ -60,7 +60,7 @@ void main() {
const lastName = 'Doe';
final booking = Booking(
id: '1',
- status: BookingStatus.current,
+ bookingStatus: BookingStatus.current,
roomNumber: '101',
startDate: DateTime.now(),
confirmationId: "",
@@ -75,7 +75,7 @@ void main() {
bookingDate: DateTime.now(),
digitalCard: true,
totalCharge: 100,
- reservationStatus: ReservationStatus.newreservation,
+ status: ReservationStatus.newreservation,
balance: 100,
maskedCardNumber: "1234567890"
);