6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit 46bb7675
Changed files
comwell_key_app/assets/translations/da-DK.json | 3 +- comwell_key_app/assets/translations/en-US.json | 3 +- .../cubit/hotel_information_cubit.dart | 2 +- comwell_key_app/lib/routing/app_router.dart | 47 ++++-- comwell_key_app/lib/routing/app_routes.dart | 1 + .../components/facilities_bottom_sheet.dart | 149 ++++++++--------- .../up_sales/components/facility_icon_text.dart | 11 +- .../lib/up_sales/components/item_counter.dart | 66 ++++++++ .../up_sales/components/room_image_carousel.dart | 77 +++++++++ .../components/up_sales_services_widget.dart | 106 ++++++------ .../components/up_sales_upgrades_widget.dart | 186 +++++++++++---------- .../lib/up_sales/cubit/up_sales_cubit.dart | 12 ++ .../lib/up_sales/cubit/up_sales_state.dart | 19 ++- .../lib/up_sales/pages/other_upgrade_page.dart | 80 +++++++++ .../lib/up_sales/pages/room_upgrade_page.dart | 80 +++++---- .../lib/up_sales/up_sale_repository.dart | 2 +- comwell_key_app/lib/up_sales/up_sales_catalog.dart | 21 +-- 17 files changed, 574 insertions(+), 291 deletions(-)
Diff
diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index ae4159e7..7496514f 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -276,5 +276,6 @@
"open_maps_error_subtitle": "Ingen kortprogram er tilgængeligt.",
"apple_maps": "Apple Kort",
"google_maps": "Google Kort",
- "add_to_booking": "Tilføj til booking"
+ "add_to_booking": "Tilføj til booking",
+ "see_all_facilities": "Se alle faciliteter"
}
\ 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 73a33f99..8d9edfc2 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -275,6 +275,7 @@
"open_maps_error_subtitle": "No maps application is available.",
"apple_maps": "Apple Maps",
"google_maps": "Google Maps",
- "add_to_booking": "Add to booking"
+ "add_to_booking": "Add to booking",
+ "see_all_facilities": "See all facilities"
}
diff --git a/comwell_key_app/lib/hotel_information/cubit/hotel_information_cubit.dart b/comwell_key_app/lib/hotel_information/cubit/hotel_information_cubit.dart
index f624a460..9e89f8ab 100644
--- a/comwell_key_app/lib/hotel_information/cubit/hotel_information_cubit.dart
+++ b/comwell_key_app/lib/hotel_information/cubit/hotel_information_cubit.dart
@@ -26,7 +26,7 @@ class HotelInformationCubit extends Cubit<HotelInformationState> {
try {
hotel = await hotelInformationRepository
.fetchHotelInformation(booking.hotelCode, culture);
- print("hotel=${hotel.toJson()}");
+
emit(state.hotelSuccess());
} catch (e) {
debugPrint("error fetching hotel information for ${booking.hotelCode}: $e");
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index a78b7ba2..019a1391 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -50,6 +50,7 @@ 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/pages/other_upgrade_page.dart';
import 'package:comwell_key_app/up_sales/pages/room_upgrade_page.dart';
import 'package:comwell_key_app/up_sales/up_sale_repository.dart';
import 'package:comwell_key_app/up_sales/up_sales_catalog.dart';
@@ -123,9 +124,7 @@ GoRouter goRouter() {
child:
BlocBuilder<HotelInformationCubit, HotelInformationState>(
builder: (context, state) {
-
- return HotelInformationPage(
- child: child);
+ return HotelInformationPage(child: child);
}),
),
);
@@ -138,15 +137,19 @@ GoRouter goRouter() {
return const HotelInformationMenu();
}),
GoRoute(
- path: "/${AppRoutes.hotelInformation.name}/${AppRoutes.spa.name}",
- name: "${AppRoutes.hotelInformation.name}/${AppRoutes.spa.name}",
+ path:
+ "/${AppRoutes.hotelInformation.name}/${AppRoutes.spa.name}",
+ name:
+ "${AppRoutes.hotelInformation.name}/${AppRoutes.spa.name}",
builder: (context, state) {
final spa = state.extra as Spa;
return SpaFacilityPage(spa: spa);
}),
GoRoute(
- path: "/${AppRoutes.hotelInformation.name}/${AppRoutes.restaurant.name}",
- name: "${AppRoutes.hotelInformation.name}/${AppRoutes.restaurant.name}",
+ path:
+ "/${AppRoutes.hotelInformation.name}/${AppRoutes.restaurant.name}",
+ name:
+ "${AppRoutes.hotelInformation.name}/${AppRoutes.restaurant.name}",
builder: (context, state) {
final restaurant = state.extra as Restaurant;
return RestaurantFacilityPage(restaurant: restaurant);
@@ -168,7 +171,8 @@ GoRouter goRouter() {
create: (BuildContext context) => ContactCubit(
contactRepository: locator<ContactRepository>(),
overviewRepository: locator<OverviewRepository>(),
- profileRepository: locator<ProfileRepository>())..init(),
+ profileRepository: locator<ProfileRepository>())
+ ..init(),
child: ContactPage(hotelCode: booking.hotelCode),
);
}),
@@ -277,12 +281,10 @@ GoRouter goRouter() {
builder: (context, state) {
final booking = state.extra as Booking;
return BlocProvider<BookingDetailsBloc>(
- create: (BuildContext context) => BookingDetailsBloc(
- booking,
- bookingDetailsRepository:
- locator<BookingDetailsRepository>(),
- profileRepository: locator<ProfileRepository>()
- ),
+ create: (BuildContext context) => BookingDetailsBloc(booking,
+ bookingDetailsRepository:
+ locator<BookingDetailsRepository>(),
+ profileRepository: locator<ProfileRepository>()),
child: const BookingDetailsPage(),
);
},
@@ -318,7 +320,8 @@ GoRouter goRouter() {
return BlocProvider(
create: (context) => PaymentCardsCubit(),
child: Builder(builder: (context) {
- final scaffold = state.uri.queryParameters[needsScaffold] == 'true';
+ final scaffold =
+ state.uri.queryParameters[needsScaffold] == 'true';
return PaymentCardsPage(needScaffold: scaffold);
}));
}),
@@ -383,7 +386,9 @@ GoRouter goRouter() {
name: AppRoutes.upSalesCatalog.name,
builder: (context, state) {
return BlocProvider(
- create: (context) => UpSalesCubit(upSaleRepository: locator<UpSaleRepository>())..init(),
+ create: (context) =>
+ UpSalesCubit(upSaleRepository: locator<UpSaleRepository>())
+ ..init(),
child: const UpSalesCatalog(),
);
},
@@ -396,6 +401,16 @@ GoRouter goRouter() {
return RoomUpgradePage(roomUpgrade: roomUpgrade);
},
),
+ GoRoute(
+ path: "/${AppRoutes.otherUpgrade.name}",
+ name: AppRoutes.otherUpgrade.name,
+ builder: (context, state) {
+ return BlocProvider(
+ create: (context) =>
+ UpSalesCubit(upSaleRepository: locator<UpSaleRepository>()),
+ child: const OtherUpgradePage(),
+ );
+ }),
/* 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 0ee65702..88ce9e04 100644
--- a/comwell_key_app/lib/routing/app_routes.dart
+++ b/comwell_key_app/lib/routing/app_routes.dart
@@ -30,4 +30,5 @@ enum AppRoutes {
myBooking,
upSalesCatalog,
roomUpgrade,
+ otherUpgrade,
}
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 4d51d284..2a77287e 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
@@ -32,85 +32,80 @@ class FacilitiesBottomSheet extends StatelessWidget {
'VÆRELSESFACILITETER':
facilities.where((f) => f.facilityType == FacilityType.room).toList(),
};
- print("grouped ${grouped}");
- return DraggableScrollableSheet(
- initialChildSize: (height - kComwellAppBarHeight) / height,
- expand: false,
- minChildSize: 0.0,
- maxChildSize: (height - kComwellAppBarHeight) / height,
- snap: true,
- builder: (context, scrollController) => Container(
- padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
- ),
- child: ListView(
- controller: scrollController,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Text('Faciliteter',
- style: theme.textTheme.headlineMedium
- ?.copyWith(fontWeight: FontWeight.bold)),
- IconButton(
- icon: const Icon(
- Icons.close,
- size: 24,
- ),
- style: IconButton.styleFrom(
- backgroundColor: sandColor[40],
- ),
- onPressed: () => Navigator.of(context).pop(),
+
+ return Container(
+ padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
+ decoration: const BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
+ ),
+ child: ListView(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text('Faciliteter', style: theme.textTheme.headlineLarge),
+ IconButton(
+ icon: const Icon(
+ Icons.close,
+ size: 24,
+ ),
+ style: IconButton.styleFrom(
+ backgroundColor: sandColor[40],
),
- ],
- ),
- const SizedBox(height: 12),
- ...grouped.entries.map((entry) => Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(entry.key,
- style: theme.textTheme.bodySmall?.copyWith(
- fontWeight: FontWeight.bold,
- color: colorHeadlineText)),
- const SizedBox(height: 8),
- Wrap(
- direction: entry.key == 'SENGETYPER'
- ? Axis.horizontal
- : Axis.vertical,
- spacing: 16,
- runSpacing: 8,
- children: entry.key == 'SENGETYPER'
- ? entry.value
- .map((f) => Container(
- width: 175,
- height: 56,
- decoration: BoxDecoration(
- border: Border.all(
- color: colorDivider,
- ),
- borderRadius: BorderRadius.circular(8),
+ onPressed: () => Navigator.of(context).pop(),
+ ),
+ ],
+ ),
+ const SizedBox(height: 12),
+ ...grouped.entries.map((entry) => Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(entry.key,
+ style: theme.textTheme.bodySmall?.copyWith(
+ fontWeight: FontWeight.bold,
+ color: colorHeadlineText)),
+ const SizedBox(height: 8),
+ Wrap(
+ direction: entry.key == 'SENGETYPER'
+ ? Axis.horizontal
+ : Axis.vertical,
+ spacing: 16,
+ runSpacing: 8,
+ children: entry.key == 'SENGETYPER'
+ ? entry.value
+ .map((f) => Container(
+ width: 175,
+ height: 56,
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: colorDivider,
),
- child: Center(
- child: FacilityIconText(facility: f)),
- ))
- .toList()
- : entry.value
- .map((f) => FacilityIconText(facility: f))
- .toList(),
- ),
- const SizedBox(height: 16),
- if (entry.key != 'SENGETYPER')
- const Divider(
- color: colorDivider,
- height: 0,
- ),
- const SizedBox(height: 24),
- ],
- )),
- ],
- ),
+ borderRadius: BorderRadius.circular(8),
+ ),
+ child: Center(
+ child: FacilityIconText(facility: f)),
+ ))
+ .toList()
+ : entry.value
+ .map((f) => FacilityIconText(facility: f, showDivider: false))
+ .toList(),
+ ),
+ const SizedBox(height: 16),
+ if (entry.key != 'SENGETYPER')
+ const Column(
+ children: [
+ Divider(
+ color: colorDivider,
+ height: 0,
+ ),
+ SizedBox(height: 12),
+ ],
+ )
+ ],
+ )),
+ const SizedBox(height: 12),
+ ],
),
);
}
diff --git a/comwell_key_app/lib/up_sales/components/facility_icon_text.dart b/comwell_key_app/lib/up_sales/components/facility_icon_text.dart
index 459021ed..989b4fcf 100644
--- a/comwell_key_app/lib/up_sales/components/facility_icon_text.dart
+++ b/comwell_key_app/lib/up_sales/components/facility_icon_text.dart
@@ -1,10 +1,12 @@
+import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/up_sales/models/room_facility.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class FacilityIconText extends StatelessWidget {
final RoomFacility facility;
- const FacilityIconText({super.key, required this.facility});
+ final bool showDivider;
+ const FacilityIconText({super.key, required this.facility, this.showDivider = true});
@override
Widget build(BuildContext context) {
@@ -14,6 +16,13 @@ class FacilityIconText extends StatelessWidget {
SvgPicture.asset(facility.icon, width: 20, height: 20),
const SizedBox(width: 4),
Text(facility.name, style: Theme.of(context).textTheme.bodySmall),
+ const SizedBox(width: 6),
+ if (showDivider)
+ Container(
+ width: 1,
+ height: 20,
+ color: colorDivider,
+ ),
],
);
}
diff --git a/comwell_key_app/lib/up_sales/components/item_counter.dart b/comwell_key_app/lib/up_sales/components/item_counter.dart
new file mode 100644
index 00000000..a31206cd
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/components/item_counter.dart
@@ -0,0 +1,66 @@
+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:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class ItemCounter extends StatelessWidget {
+ const ItemCounter({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+
+
+ return BlocBuilder<UpSalesCubit, UpSalesState>(
+ builder: (context, state) {
+ final theme = Theme.of(context);
+ final cubit = context.read<UpSalesCubit>();
+ return Expanded(
+ child: Container(
+ width: double.infinity,
+ color: Colors.white,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Row(
+ children: [
+ // Minus button
+ InkWell(
+ onTap: cubit.decrement,
+ borderRadius: BorderRadius.circular(24),
+ child: Container(
+ width: 44,
+ height: 44,
+ decoration: const BoxDecoration(
+ color: Colors.black,
+ shape: BoxShape.circle,
+ ),
+ child: const Icon(Icons.remove, color: Colors.white),
+ ),
+ ),
+ const SizedBox(width: 16),
+ Text('${cubit.state.quantity}', style: theme.textTheme.headlineSmall),
+ const SizedBox(width: 16),
+ // Plus button
+ InkWell(
+ onTap: cubit.increment,
+ borderRadius: BorderRadius.circular(24),
+ child: Container(
+ width: 44,
+ height: 44,
+ decoration: const BoxDecoration(
+ color: Colors.black,
+ shape: BoxShape.circle,
+ ),
+ child: const Icon(Icons.add, color: Colors.white),
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+ );
+ }
+}
\ No newline at end of file
diff --git a/comwell_key_app/lib/up_sales/components/room_image_carousel.dart b/comwell_key_app/lib/up_sales/components/room_image_carousel.dart
new file mode 100644
index 00000000..39269d01
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/components/room_image_carousel.dart
@@ -0,0 +1,77 @@
+import 'package:flutter/material.dart';
+
+class RoomImageCarousel extends StatefulWidget {
+ final List<String> images;
+ const RoomImageCarousel({super.key, required this.images});
+
+ @override
+ State<RoomImageCarousel> createState() => _RoomImageCarouselState();
+}
+
+class _RoomImageCarouselState extends State<RoomImageCarousel> {
+ late PageController _pageController;
+ int _currentPage = 0;
+
+ @override
+ void initState() {
+ super.initState();
+ _pageController = PageController();
+ }
+
+ @override
+ void dispose() {
+ _pageController.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final height = MediaQuery.of(context).size.height;
+ return SizedBox(
+ width: double.infinity,
+ height: height * 0.5,
+ child: Stack(
+ children: [
+ PageView.builder(
+ controller: _pageController,
+ onPageChanged: (index) {
+ setState(() {
+ _currentPage = index;
+ });
+ },
+ itemCount: widget.images.length,
+ itemBuilder: (context, index) {
+ return Image.asset(
+ widget.images[index],
+ fit: BoxFit.cover,
+ );
+ },
+ ),
+ // Dot indicators
+ Positioned(
+ bottom: 16,
+ left: 0,
+ right: 0,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: List.generate(
+ widget.images.length,
+ (index) => Container(
+ margin: const EdgeInsets.symmetric(horizontal: 4),
+ width: 8,
+ height: 8,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ color: _currentPage == index
+ ? Colors.white
+ : Colors.white.withValues(alpha: 0.5),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
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 f967176e..2cfb70a2 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
@@ -22,65 +22,67 @@ class UpSalesServicesWidget extends StatelessWidget {
create: (context) => UpSalesCubit(upSaleRepository: UpSaleRepository()),
child: BlocBuilder<UpSalesCubit, UpSalesState>(builder: (context, state) {
final cubit = context.read<UpSalesCubit>();
- return Padding(
- padding: const EdgeInsets.only(right: 16),
- child: Container(
- width: width,
- height: height,
- padding: const EdgeInsets.all(24),
- 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: cubit.toggleSelected),
- ],
- ),
+ Text('early_checkin'.tr(),
+ style: theme.textTheme.headlineMedium),
],
),
- ],
- ),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- const TagWidget(text: 'POPULÆR'),
- const SizedBox(height: 8),
- Text(
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Row(
+ children: [
+ Text(
+ '200 kr.',
+ style: theme.textTheme.headlineMedium,
+ ),
+ const SizedBox(width: 8),
+ // ComwellRadioButton(selected: cubit.state.selected, onTap: cubit.toggleSelected),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ 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.bodyMedium?.copyWith(
+ 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 b42cfd01..fc43779f 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
@@ -15,7 +15,14 @@ class UpSalesUpgradesWidget extends StatelessWidget {
final double height;
final RoomUpgrade roomUpgrade;
final bool isSelected;
- const UpSalesUpgradesWidget({super.key, this.width = 328, this.height = 268, required this.roomUpgrade, this.isSelected = false});
+ final String routeName;
+ const UpSalesUpgradesWidget(
+ {super.key,
+ this.width = 328,
+ this.height = 268,
+ required this.roomUpgrade,
+ this.isSelected = false,
+ required this.routeName});
@override
Widget build(BuildContext context) {
@@ -23,107 +30,108 @@ class UpSalesUpgradesWidget extends StatelessWidget {
return BlocBuilder<UpSalesCubit, UpSalesState>(builder: (context, state) {
final cubit = context.read<UpSalesCubit>();
return Container(
- width: width,
- height: height,
- margin: const EdgeInsets.all(8),
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(10),
- border: Border.all(color: colorDivider, width: 1),
- ),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Stack(
+ width: width,
+ height: height,
+ margin: const EdgeInsets.only(left: 16, right: 8, top: 8, bottom: 16),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(10),
+ border: Border.all(color: colorDivider, width: 1),
+ ),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
children: [
- ClipRRect(
- borderRadius: const BorderRadius.only(
- topLeft: Radius.circular(10),
- topRight: Radius.circular(10),
- ),
- child: Image.asset(
- roomUpgrade.images.first,
- height: 180,
- width: double.infinity,
- fit: BoxFit.cover,
- ),
- ),
- if (roomUpgrade.tags.firstOrNull != null)
- Positioned(
- top: 16,
- right: 16,
- child: Container(
- padding:
- const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(32),
+ Stack(
+ children: [
+ ClipRRect(
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(10),
+ topRight: Radius.circular(10),
+ ),
+ child: Image.asset(
+ roomUpgrade.images.first,
+ height: 180,
+ width: double.infinity,
+ fit: BoxFit.cover,
+ ),
),
- child: Text(
- '${roomUpgrade.tags.first} m2',
- style:
- theme.textTheme.headlineMedium?.copyWith(fontSize: 11),
- ),
- ),
+ if (roomUpgrade.tags.firstOrNull != null)
+ Positioned(
+ top: 16,
+ right: 16,
+ child: Container(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 12, vertical: 4),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(32),
+ ),
+ child: Text(
+ '${roomUpgrade.tags.first} m2',
+ style: theme.textTheme.headlineMedium
+ ?.copyWith(fontSize: 11),
+ ),
+ ),
+ ),
+ ],
),
- ],
- ),
- Padding(
- padding: const EdgeInsets.only(left: 8, right: 8, top: 16, bottom: 8),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ Padding(
+ padding:
+ const EdgeInsets.only(left: 8, right: 8, top: 16, bottom: 8),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Flexible(
- child: Text(
- roomUpgrade.name,
- style: theme.textTheme.headlineMedium,
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- ),
- ),
Row(
- mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Text(
- '${roomUpgrade.price} kr.',
- style: theme.textTheme.headlineMedium,
+ Flexible(
+ child: Text(
+ roomUpgrade.name,
+ style: theme.textTheme.headlineMedium,
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ ),
),
- const SizedBox(width: 8),
- ComwellRadioButton(
- selected: isSelected,
- onTap: () => cubit.toggleSelected(),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ '${roomUpgrade.price} kr.',
+ style: theme.textTheme.headlineMedium,
+ ),
+ const SizedBox(width: 8),
+ ComwellRadioButton(
+ selected: isSelected,
+ onTap: () => cubit.toggleSelected(),
+ ),
+ ],
),
],
),
- ],
- ),
- const SizedBox(height: 8),
- GestureDetector(
- onTap: () {
- context.pushNamed(AppRoutes.roomUpgrade.name, extra: roomUpgrade);
- },
- child: Text(
- 'read_more_up_sales'.tr(),
- style: theme.textTheme.bodySmall?.copyWith(
- color: sandColor[80],
- decoration: TextDecoration.underline,
- decorationColor: sandColor[80],
+ const SizedBox(height: 8),
+ GestureDetector(
+ onTap: () {
+ context.pushNamed(routeName, extra: roomUpgrade);
+ },
+ child: Text(
+ 'read_more_up_sales'.tr(),
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: sandColor[80],
+ decoration: TextDecoration.underline,
+ decorationColor: sandColor[80],
+ ),
+ ),
),
- ),
+ ],
),
- ],
- ),
+ ),
+ ],
),
- ],
- ),
- ),
+ ),
],
),
);
diff --git a/comwell_key_app/lib/up_sales/cubit/up_sales_cubit.dart b/comwell_key_app/lib/up_sales/cubit/up_sales_cubit.dart
index 29acb03a..60fa9ee8 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
@@ -25,7 +25,19 @@ class UpSalesCubit extends Cubit<UpSalesState> {
}
}
+ void increment() {
+ print('increment ${state.quantity}');
+ emit(state.copyWith(quantity: state.quantity + 4));
+ }
+
+ void decrement() {
+ if (state.quantity > 0) {
+ emit(state.copyWith(quantity: state.quantity - 1));
+ }
+ }
+
void onContinue() {
emit(state.copyWith(selected: false));
}
+
}
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 bc36f38d..80cc04c0 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
@@ -6,7 +6,8 @@ class UpSalesState extends Equatable {
final Iterable<RoomUpgrade> upSales;
final Error? error;
final bool isLoading;
- const UpSalesState({required this.selected, required this.upSales, this.error, required this.isLoading});
+ final int quantity;
+ const UpSalesState({required this.selected, required this.upSales, this.error, required this.isLoading, this.quantity = 0});
@override
List<Object?> get props => [selected, upSales];
@@ -15,35 +16,41 @@ class UpSalesState extends Equatable {
: selected = false,
upSales = [],
error = null,
- isLoading = false;
+ isLoading = false,
+ quantity = 0;
UpSalesState.error({required this.error})
: selected = false,
upSales = [],
- isLoading = false;
+ isLoading = false,
+ quantity = 0;
UpSalesState.loading()
: selected = false,
upSales = [],
error = null,
- isLoading = true;
+ isLoading = true,
+ quantity = 0;
const UpSalesState.loaded({required this.upSales})
: selected = false,
error = null,
- isLoading = false;
+ isLoading = false,
+ quantity = 0;
UpSalesState copyWith({
bool? selected,
Iterable<RoomUpgrade>? upSales,
bool? isLoading,
Error? error,
+ int? quantity,
}) {
return UpSalesState(
selected: selected ?? this.selected,
upSales: upSales ?? this.upSales,
isLoading: isLoading ?? this.isLoading,
- error: error ?? this.error
+ error: error ?? this.error,
+ quantity: quantity ?? this.quantity,
);
}
}
\ 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
new file mode 100644
index 00000000..8d3f3d1c
--- /dev/null
+++ b/comwell_key_app/lib/up_sales/pages/other_upgrade_page.dart
@@ -0,0 +1,80 @@
+import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
+import 'package:comwell_key_app/up_sales/components/item_counter.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import '../../themes/light_theme.dart';
+import '../components/up_sales_bottom_button.dart';
+
+class OtherUpgradePage extends StatefulWidget {
+ const OtherUpgradePage({super.key});
+
+ @override
+ State<OtherUpgradePage> createState() => _OtherUpgradePageState();
+}
+
+class _OtherUpgradePageState extends State<OtherUpgradePage> {
+ int quantity = 2;
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return Scaffold(
+ backgroundColor: Colors.white,
+ appBar: const ComwellAppBar(),
+ extendBodyBehindAppBar: true,
+ body: Column(
+ children: [
+ // Image
+ Container(
+ width: double.infinity,
+ height: 320,
+ decoration: BoxDecoration(
+ image: DecorationImage(
+ image: NetworkImage('https://images.unsplash.com/photo-1504674900247-0877df9cc836'),
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ // Card
+ Container(
+ width: double.infinity,
+ color: Colors.white,
+ padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text('En flaske bobler', style: theme.textTheme.headlineSmall),
+ Text('495 kr.', style: theme.textTheme.headlineSmall),
+ ],
+ ),
+ const SizedBox(height: 12),
+ Text(
+ 'Nyd en flaske cava i værelset ved ankomst.\nServeret kølet med et sæt glas.',
+ style: theme.textTheme.bodyMedium,
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ bottomNavigationBar: Container(
+ color: Colors.white,
+ padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ const ItemCounter(),
+ Expanded(
+ child: UpSalesBottomButton(onContinue: () {}, children: [
+ Text('Tilføj til booking', style: theme.textTheme.headlineSmall),
+ ]),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
\ No newline at end of file
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 82eca889..59ef7f69 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
@@ -3,12 +3,15 @@ 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/facilities_bottom_sheet.dart';
import 'package:comwell_key_app/up_sales/components/facility_icon_text.dart';
+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:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
import 'package:comwell_key_app/up_sales/models/room_facility.dart';
import 'package:comwell_key_app/up_sales/components/tags.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
class RoomUpgradePage extends StatefulWidget {
@@ -22,50 +25,50 @@ 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
];
+
+
+
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- final height = MediaQuery.of(context).size.height;
-
+
return Scaffold(
extendBodyBehindAppBar: true,
appBar: const ComwellAppBar(),
- backgroundColor: const Color(0xFFF2F2F2),
- body: Column(
- children: [
- //TODO: Change to ImageWidget when we have the image url
- SizedBox(
- width: double.infinity,
- height: height * 0.5,
- child: Image.asset(
- widget.roomUpgrade.images.first,
- fit: BoxFit.cover,
- ),
+ 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
),
- Expanded(
- child: Container(
- width: double.infinity,
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(24),
- topRight: Radius.circular(24),
+ 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),
+ ),
),
- ),
- child: Padding(
- padding:
- const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
- child: SingleChildScrollView(
+ 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,
@@ -104,18 +107,18 @@ class _RoomUpgradePageState extends State<RoomUpgradePage> {
const SizedBox(height: 24),
// Facilities row
Wrap(
- spacing: 16,
+ spacing: 8,
runSpacing: 8,
children: [
...widget.roomUpgrade.facilities
- .map((f) => FacilityIconText(facility: f)),
+ .map((f) => FacilityIconText(facility: f, showDivider: true)),
GestureDetector(
onTap: () => _showFacilitiesSheet(context),
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 4.0),
child: Text(
- 'Se alle faciliteter',
+ 'see_all_facilities'.tr(),
style: theme.textTheme.bodySmall?.copyWith(
color: sandColor,
decoration: TextDecoration.underline,
@@ -131,12 +134,12 @@ class _RoomUpgradePageState extends State<RoomUpgradePage> {
),
),
),
- ),
+ // Booking button
+ ],
),
- // Booking button
- ],
+ ),
),
- bottomSheet: UpSalesBottomButton(onContinue: () {}, children: [
+ bottomNavigationBar: UpSalesBottomButton(onContinue: () {}, children: [
Text(
"add_to_booking".tr(),
style: theme.textTheme.headlineSmall?.copyWith(color: Colors.white),
@@ -150,13 +153,22 @@ class _RoomUpgradePageState extends State<RoomUpgradePage> {
}
void _showFacilitiesSheet(BuildContext context) {
+ final height = MediaQuery.of(context).size.height;
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
+ enableDrag: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
),
- builder: (context) => FacilitiesBottomSheet(facilities: allFacilities),
+ builder: (context) {
+ return ConstrainedBox(
+ constraints: BoxConstraints(
+ maxHeight: height - kComwellAppBarHeight,
+ ),
+ child: FacilitiesBottomSheet(facilities: allFacilities),
+ );
+ },
);
}
}
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 2595d8db..65862e7e 100644
--- a/comwell_key_app/lib/up_sales/up_sale_repository.dart
+++ b/comwell_key_app/lib/up_sales/up_sale_repository.dart
@@ -25,7 +25,7 @@ final List<RoomUpgradeDTO> mockRoomUpgrades = [
RoomUpgradeDTO(
name: 'Standard Double Room',
price: '1200',
- images: ['assets/images/welcome_image.jpeg'],
+ images: ['assets/images/welcome_image.jpeg', 'assets/images/current_room.png', 'assets/images/no_current_bookings_background.jpeg'],
description:
'A cozy room with a double bed, perfect for couples or solo travelers seeking comfort and convenience. A cozy room with a double bed, perfect for couples or solo travelers seeking comfort and convenience. A cozy room with a double bed, perfect for couples or solo travelers seeking comfort and convenience.',
id: '1',
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 1721a1b4..e3a7dc11 100644
--- a/comwell_key_app/lib/up_sales/up_sales_catalog.dart
+++ b/comwell_key_app/lib/up_sales/up_sales_catalog.dart
@@ -1,4 +1,5 @@
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/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';
@@ -43,8 +44,7 @@ class UpSalesCatalog extends StatelessWidget {
child: Text('services'.tr(),
style: theme.textTheme.headlineMedium),
),
- const SizedBox(height: 16),
- const SizedBox(width: 20),
+ const SizedBox(height: 8),
_buildServicesCatalog(context, cubit),
const SizedBox(height: 24),
Padding(
@@ -52,8 +52,7 @@ class UpSalesCatalog extends StatelessWidget {
child: Text('room_upgrades'.tr(),
style: theme.textTheme.headlineMedium),
),
- const SizedBox(height: 16),
- const SizedBox(width: 20),
+ const SizedBox(height: 8),
_buildRoomUpgradeCatalog(context, cubit),
const SizedBox(height: 24),
Padding(
@@ -61,8 +60,7 @@ class UpSalesCatalog extends StatelessWidget {
child: Text('other_up_sales'.tr(),
style: theme.textTheme.headlineMedium),
),
- const SizedBox(height: 16),
- const SizedBox(width: 20),
+ const SizedBox(height: 8),
_buildOtherUpSalesCatalog(context, cubit),
const SizedBox(height: 24),
],
@@ -82,12 +80,12 @@ class UpSalesCatalog extends StatelessWidget {
Widget _buildServicesCatalog(BuildContext context, UpSalesCubit cubit) {
return SizedBox(
- height: 258, // Height of the UpSalesServicesWidget
+ height: 180, // Height of the UpSalesServicesWidget
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: cubit.upSales.length,
itemBuilder: (context, index) {
- return UpSalesServicesWidget(width: 328, height: 252);
+ return UpSalesServicesWidget(width: 328);
},
),
);
@@ -98,8 +96,6 @@ class UpSalesCatalog extends StatelessWidget {
.where((roomUpgrade) => roomUpgrade.type == UpgradeType.room)
.toList();
- print("roomUpSales ${roomUpSales}");
-
return SizedBox(
height: 289, // Height of the UpSalesUpgradesWidget
child: ListView.builder(
@@ -111,6 +107,7 @@ class UpSalesCatalog extends StatelessWidget {
height: 268,
roomUpgrade: roomUpSales.elementAt(index),
isSelected: cubit.state.selected,
+ routeName: AppRoutes.roomUpgrade.name,
);
},
),
@@ -122,9 +119,8 @@ class UpSalesCatalog extends StatelessWidget {
.where((roomUpgrade) => roomUpgrade.type == UpgradeType.other)
.toList();
- print("otherUpSales ${otherUpSales}");
return SizedBox(
- height: 289, // Height of the UpSalesUpgradesWidget
+ height: 289,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: otherUpSales.length,
@@ -134,6 +130,7 @@ class UpSalesCatalog extends StatelessWidget {
height: 268,
roomUpgrade: otherUpSales.elementAt(index),
isSelected: cubit.state.selected,
+ routeName: AppRoutes.otherUpgrade.name,
);
},
),